File: UUID.hs

package info (click to toggle)
git-annex 10.20250416-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 73,572 kB
  • sloc: haskell: 90,656; javascript: 9,103; sh: 1,469; makefile: 211; perl: 137; ansic: 44
file content (136 lines) | stat: -rw-r--r-- 3,326 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
{- git-annex UUID type
 -
 - Copyright 2011-2023 Joey Hess <id@joeyh.name>
 -
 - Licensed under the GNU AGPL version 3 or higher.
 -}

{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE CPP #-}

module Types.UUID where

import qualified Data.ByteString as B
import qualified Data.ByteString.Short as SB
import qualified Data.Text as T
import qualified Data.Map as M
import qualified Data.UUID as U
import Data.Maybe
import Data.String
import Data.ByteString.Builder
import Control.DeepSeq
import qualified Data.Semigroup as Sem

import Common
import Git.Types (ConfigValue(..))
import Utility.QuickCheck
import Utility.Aeson
import qualified Utility.SimpleProtocol as Proto

-- A UUID is either an arbitrary opaque string, or UUID info may be missing.
data UUID = NoUUID | UUID B.ByteString
	deriving (Eq, Ord, Show, Read)

instance NFData UUID where
	rnf NoUUID = ()
	rnf (UUID b) = rnf b

class FromUUID a where
	fromUUID :: UUID -> a

class ToUUID a where
	toUUID :: a -> UUID

instance FromUUID UUID where
	fromUUID = id

instance ToUUID UUID where
	toUUID = id

instance FromUUID B.ByteString where
	fromUUID (UUID u) = u
	fromUUID NoUUID = B.empty

instance ToUUID B.ByteString where
	toUUID b
		| B.null b = NoUUID
		| otherwise = UUID b

instance FromUUID SB.ShortByteString where
	fromUUID (UUID u) = SB.toShort u
	fromUUID NoUUID = SB.empty

instance ToUUID SB.ShortByteString where
	toUUID b
		| SB.null b = NoUUID
		| otherwise = UUID (SB.fromShort b)

#ifdef WITH_OSPATH
-- OsPath is a ShortByteString internally, so this is the most
-- efficient conversion.
instance FromUUID OsPath where
	fromUUID s = toOsPath (fromUUID s :: SB.ShortByteString)

instance ToUUID OsPath where
	toUUID s = toUUID (fromOsPath s :: SB.ShortByteString)
#endif

instance FromUUID String where
	fromUUID s = decodeBS (fromUUID s)

instance ToUUID String where
	toUUID s = toUUID (encodeBS s)

instance FromUUID ConfigValue where
	fromUUID s = (ConfigValue (fromUUID s))

instance ToUUID ConfigValue where
	toUUID (ConfigValue v) = toUUID v
	toUUID NoConfigValue = NoUUID

-- There is no matching FromUUID U.UUID because a git-annex UUID may
-- be NoUUID or perhaps contain something not allowed in a canonical UUID.
instance ToUUID U.UUID where
	toUUID = toUUID . U.toASCIIBytes

instance ToJSON' UUID where
	toJSON' (UUID u) = toJSON' u
	toJSON' NoUUID = toJSON' ""

instance FromJSON UUID where
	parseJSON (String t)
		| isUUID s = pure (toUUID s)
		| otherwise = mempty
	  where
		s = T.unpack t
	parseJSON _ = mempty

buildUUID :: UUID -> Builder
buildUUID (UUID b) = byteString b
buildUUID NoUUID = mempty

isUUID :: String -> Bool
isUUID = isJust . U.fromString

-- A description of a UUID.
newtype UUIDDesc = UUIDDesc B.ByteString
	deriving (Eq, Sem.Semigroup, Monoid, IsString)

fromUUIDDesc :: UUIDDesc -> String
fromUUIDDesc (UUIDDesc d) = decodeBS d

toUUIDDesc :: String -> UUIDDesc
toUUIDDesc = UUIDDesc . encodeBS

type UUIDDescMap = M.Map UUID UUIDDesc

instance Proto.Serializable UUID where
	serialize = fromUUID
	deserialize = Just . toUUID

instance Arbitrary UUID where
	arbitrary = frequency [(1, return NoUUID), (3, UUID <$> arb)]
	  where
		arb = encodeBS <$> listOf1 (elements uuidchars)
		uuidchars = '-' : ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9']