-
Notifications
You must be signed in to change notification settings - Fork 0
/
unicly-string-uuid.lisp
161 lines (145 loc) · 8.1 KB
/
unicly-string-uuid.lisp
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
;;; :FILE-CREATED <Timestamp: #{2011-08-17T16:40:17-04:00Z}#{11333} - by MON>
;;; :FILE unicly/unicly-string-uuid.lisp
;;; ==============================
(in-package #:unicly)
(declaim (inline uuid-hex-vector-parse-time-low
uuid-hex-vector-parse-time-mid
uuid-hex-vector-parse-time-high-and-version
uuid-hex-vector-parse-clock-seq-and-reserved
uuid-hex-vector-parse-clock-seq-low
uuid-hex-vector-parse-node))
;;
(def-indexed-hexstring-integer-parser "TIME-LOW" 0 uuid-hex-string-8 0 8 uuid-ub32)
(def-indexed-hexstring-integer-parser "TIME-MID" 1 uuid-hex-string-4 0 4 uuid-ub16)
(def-indexed-hexstring-integer-parser "TIME-HIGH-AND-VERSION" 2 uuid-hex-string-4 0 4 uuid-ub16)
(def-indexed-hexstring-integer-parser "CLOCK-SEQ-AND-RESERVED" 3 uuid-hex-string-4 0 2 uuid-ub8)
(def-indexed-hexstring-integer-parser "CLOCK-SEQ-LOW" 3 uuid-hex-string-4 2 4 uuid-ub8)
(def-indexed-hexstring-integer-parser "NODE" 4 uuid-hex-string-12 0 12 uuid-ub48)
;;; ==============================
;; :TODO This should also check for a uuid-hex-string-32, and return a symbol
;; naming the appropriate dispatch function for the correct offsets.
(declaim (inline make-uuid-from-string-if))
(defun make-uuid-from-string-if (uuid-hex-string-36-if)
(declare (inline uuid-hex-string-36-p)
(optimize (speed 3)))
(multiple-value-bind (if-36 vector-5-or-null-uuid) (uuid-hex-string-36-p uuid-hex-string-36-if)
(declare (boolean if-36)
(type (or null function uuid-simple-vector-5) vector-5-or-null-uuid))
(if if-36
(etypecase vector-5-or-null-uuid
(compiled-function (the compiled-function vector-5-or-null-uuid))
(function (the function vector-5-or-null-uuid))
(uuid-simple-vector-5 (the uuid-simple-string-vector-5 vector-5-or-null-uuid)))
#-:MON
(error "Arg UUID-HEX-STRING-36-IF not `uuid-hex-string-36-p'~% ~
got: ~S~% ~
type-of: ~S~%" uuid-hex-string-36-if (type-of uuid-hex-string-36-if))
#+(and :IS-MON :MON)
(MON:SIMPLE-ERROR-MON :w-sym 'make-uuid-from-string-if
:w-type 'function
:w-spec "Arg UUID-HEX-STRING-36-IF not `uuid-hex-string-36-p'"
:w-got uuid-hex-string-36-if
:w-type-of t
:signal-or-only nil))))
;; (multiple-value-bind (if-36 vector-5-or-null-uuid) (unicly::uuid-hex-string-36-p "00000000-0000-0000-0000-000000000000")
;; (list if-36 vector-5-or-null-uuid))
;; (multiple-value-bind (if-36 vector-5-or-null-uuid) (unicly::uuid-hex-string-36-p "6ba7b810-9dad-11d1-80b4-00c04fd430c8")
;; (list if-36 vector-5-or-null-uuid))
;; (typep (unicly::make-uuid-from-string-if "6ba7b810-9dad-11d1-80b4-00c04fd430c8") '(simple-array simple-string (5)))
;; (unicly::make-uuid-from-string-if "6ba7b810-9dad-11d1-80b4-00c04fd430c8")
;; (typep (unicly::make-uuid-from-string-if "00000000-0000-0000-0000-000000000000") 'compiled-function)
;; (compiled-function-p (nth-value 1 (unicly::uuid-hex-string-36-p "00000000-0000-0000-0000-000000000000")))
;;
;; (make-uuid-from-string "6ba7b810-9dad-11d1-80b4-00c04fd430c8")
;;; ==============================
;; :TODO This should also check for a uuid-hex-string-32 and parse at different
;; offsets via dispatch to the appropriate function.
;;
;; :TODO Figure out what to do about subclasses of
;; `unique-universal-identifier'. If we keep the same separation for
;; `make-uuid-from-string' as we currently have between
;; `make-v5-uuid' and `def-make-v4-uuid-extended'
;; then a macro `def-make-uuid-from-string-extended' may require duplicating
;; much of the functionality defined below. However, it won't require us to make
;; dispambiguations in the etypecase form.
;;
;; :NOTE What about `cl:read-from-string' instead of `cl:parse-integer' e.g.:
;; (let ((*read-base* 16)) (read-from-string "88"))
;; No. When asked on #lisp noting that the bounds fo string and its contents are
;; known and pre-verified to be all hexadecimal chars -- nyef says:
;; ,----
;; | Use PARSE-INTEGER. It's more efficient, and makes an explicit
;; | statement about what syntax you're expecting as input.
;; `----
(defun make-uuid-from-string (uuid-or-hex-string-36)
(declare (type (or unique-universal-identifier string) uuid-or-hex-string-36)
(inline make-uuid-from-string-if
uuid-hex-string-36-p
uuid-hex-vector-parse-time-low uuid-hex-vector-parse-time-mid
uuid-hex-vector-parse-time-high-and-version
uuid-hex-vector-parse-clock-seq-and-reserved
uuid-hex-vector-parse-clock-seq-low uuid-hex-vector-parse-node)
(optimize (speed 3)))
(let ((chk-uuid-str (etypecase uuid-or-hex-string-36
(unique-universal-identifier
(return-from make-uuid-from-string (the unique-universal-identifier (uuid-copy-uuid uuid-or-hex-string-36))))
(string
(let ((vec-or-fun (make-uuid-from-string-if uuid-or-hex-string-36)))
(declare (type (or function compiled-function uuid-simple-vector-5) vec-or-fun))
(etypecase vec-or-fun
((or function compiled-function)
(let ((null-id (funcall vec-or-fun)))
(declare (type unique-universal-identifier-null null-id))
(return-from make-uuid-from-string
(the unique-universal-identifier-null null-id))))
(uuid-simple-vector-5 (the uuid-simple-string-vector-5 vec-or-fun))))))))
(declare ;;(optimize (speed 3))
;; (type uuid-simple-vector-5 chk-uuid-str)
(type uuid-simple-string-vector-5 chk-uuid-str))
(the unique-universal-identifier
(make-instance 'unique-universal-identifier
:%uuid_time-low (uuid-hex-vector-parse-time-low chk-uuid-str)
:%uuid_time-mid (uuid-hex-vector-parse-time-mid chk-uuid-str)
:%uuid_time-high-and-version (uuid-hex-vector-parse-time-high-and-version chk-uuid-str)
:%uuid_clock-seq-and-reserved (uuid-hex-vector-parse-clock-seq-and-reserved chk-uuid-str)
:%uuid_clock-seq-low (uuid-hex-vector-parse-clock-seq-low chk-uuid-str)
:%uuid_node (uuid-hex-vector-parse-node chk-uuid-str)))))
;;; ==============================
#+(or)
(defun uuid-string-to-sha1-byte-array (string)
(declare (type string string))
(let ((digester (ironclad:make-digest :sha1)))
(declare (ironclad:sha1 digester))
(ironclad:update-digest digester
#+sbcl (sb-ext:string-to-octets string :external-format :UTF-8)
#-sbcl (flexi-streams:string-to-octets string :external-format :UTF-8))
(ironclad:produce-digest digester)))
#+(or)
(defun uuid-string-to-md5-byte-array (string)
(declare (type string string))
(let ((digester (ironclad:make-digest :MD5)))
(declare (type ironclad:MD5 digester))
(ironclad:update-digest digester
#+sbcl (sb-ext:string-to-octets string :external-format :UTF-8)
#-sbcl (flexi-streams:string-to-octets string :external-format :UTF-8))
(ironclad:produce-digest digester)))
;; :SOURCE cl-crypto/source/aes16.lisp
#+(or)
(defun hex-str->bin-array (hex-str)
(let* ((bin-len (/ (length hex-str) 2))
(bin (make-array bin-len :element-type 'uint-8)))
(dotimes (i bin-len)
(setf (aref bin i)
(parse-integer hex-str :radix 16
:start (* 2 i)
:end (* 2 (1+ i)))))
bin))
;;; ==============================
;; Local Variables:
;; indent-tabs-mode: nil
;; show-trailing-whitespace: t
;; mode: lisp-interaction
;; package: unicly
;; End:
;;; ==============================
;;; EOF