11module
22
33public import Binary.Basic
4- meta import Lean
54
65namespace Binary
76
@@ -11,15 +10,14 @@ public section
1110def fail (msg : String) : Get α :=
1211 throw (.userError msg)
1312
14- @[specialize]
1513def many (p : Get α) : Get (Array α) := do
1614 let mut data := #[]
1715 repeat
1816 let some x ← optional p | break
1917 data := data.push x
2018 return data
2119
22- @ [inline, specialize ]
20+ @[inline]
2321def many1 (p : Get α) : Get (Array α) := do
2422 let first ← p
2523 let rest ← many p
@@ -42,9 +40,6 @@ def notFollowedBy (p : Get α) : Get Unit := fun d =>
4240 | .error _ _ => DecodeResult.success () d
4341 | .pending _ => DecodeResult.error (.userError "unexpected pending lookahead" ) d
4442
45- -- TODO: refactor following definitions for performance
46-
47- @ [inline, specialize]
4843def takeAtLeast (n : Nat) (p : Get α) : Get (Array α) := do
4944 let mut r := Array.emptyWithCapacity n
5045 repeat
@@ -57,39 +52,39 @@ def takeAtLeast (n : Nat) (p : Get α) : Get (Array α) := do
5752 return r
5853
5954/-- inclusive -/
60- @ [inline, specialize ]
55+ @[inline]
6156def takeUpTo (n : Nat) (p : Get α) : Get (Array α) := do
62- let mut r := #[]
63- repeat
57+ let mut r := Array.emptyWithCapacity n
58+ while true do
6459 if r.size == n then break
6560 let some x ← optional p | break
6661 r := r.push x
6762 return r
6863
6964/-- inclusive -/
70- @ [inline, specialize ]
65+ @[inline]
7166def take1UpTo (n : Nat) (p : Get α) : Get (Array α) := do
7267 let x ← p
73- let mut r := #[x]
68+ let mut r := (Array.emptyWithCapacity n).push x
7469 repeat
7570 if r.size == n then break
7671 let some x ← optional p | break
7772 r := r.push x
7873 return r
7974
80- @ [inline, specialize ]
75+ @[inline]
8176def takeN (n : Nat) (p : Get α) : Get (Array α) := do
82- let mut r := Array.emptyWithCapacity 0
77+ let mut r := Array.emptyWithCapacity n
8378 repeat
8479 if r.size == n then break
8580 let x ← p
8681 r := r.push x
8782 return r
8883
8984/--inclusive on both sides -/
90- @ [inline, specialize ]
85+ @[inline]
9186def takeRange (min max : Nat) (p : Get α) : Get (Array α) := do
92- let mut r := Array.emptyWithCapacity min
87+ let mut r := Array.emptyWithCapacity max
9388 repeat
9489 if r.size == min then break
9590 let x ← p
@@ -100,7 +95,7 @@ def takeRange (min max : Nat) (p : Get α) : Get (Array α) := do
10095 r := r.push x
10196 return r
10297
103- @ [inline, specialize ]
98+ @[inline]
10499def sepBy (x : Get α) (sep : Get Unit) : Get (Array α) := do
105100 let some l ← optional x | return #[]
106101 let mut t := #[l]
@@ -109,7 +104,7 @@ def sepBy (x : Get α) (sep : Get Unit) : Get (Array α) := do
109104 t := t.push v
110105 return t
111106
112- @ [inline, specialize ]
107+ @[inline]
113108def sepBy1 (x : Get α) (s : Get Unit) : Get (Array α) := do
114109 let l ← x
115110 let mut t := #[l]
@@ -118,20 +113,20 @@ def sepBy1 (x : Get α) (s : Get Unit) : Get (Array α) := do
118113 t := t.push v
119114 return t
120115
121- @ [inline, specialize ]
116+ @[inline]
122117def sepByUpTo (n : Nat) (x : Get α) (s : Get Unit) : Get (Array α) := do
123118 let some l ← optional x | return #[]
124- let mut t := #[l]
119+ let mut t := (Array.emptyWithCapacity n).push l
125120 repeat
126121 if t.size ≥ n then break
127122 let some v ← optional (s *> x) | break
128123 t := t.push v
129124 return t
130125
131- @ [inline, specialize ]
126+ @[inline]
132127def sepBy1UpTo (n : Nat) (x : Get α) (s : Get Unit) : Get (Array α) := do
133128 let l ← x
134- let mut t := #[l]
129+ let mut t := (Array.emptyWithCapacity n).push l
135130 repeat
136131 if t.size ≥ n then break
137132 let some v ← optional (s *> x) | break
@@ -182,72 +177,62 @@ end
182177
183178namespace Primitive
184179
185- variable {ω m} [Monad m] [STWorld ω m] [MonadLiftT (ST ω) m]
186-
187- private meta def generate_prim (le : Bool) (unsigned : Bool) (type : Lean.TSyntax `ident) (size : Lean.TSyntax `num) : Lean.MacroM Lean.Command := do
188- let len := size.getNat
189- if len = 0 then
190- Lean.Macro.throwErrorAt size "size cannot be 0"
191- let newSize := Lean.TSyntax.mk <| size.raw.setArg 0 (size.raw[0 ].setAtomVal s! "{ len - 1 } " )
192- let d ← Lean.mkIdent <$> Lean.Macro.addMacroScope `d
193- let d_offset ← `($(Lean.mkIdent `Decoder.offset) $d:ident)
194- let d_data ← `($(Lean.mkIdent `Decoder.data) $d:ident)
195- let d_data_size ← `($(Lean.mkIdent `ByteArray.size) ($(Lean.mkIdent `Decoder.data) $d:ident))
196- let ns := List.range len
197- let ts ← ns.mapM fun x => do
198- let y ←
199- if unsigned then
200- `($(Lean.mkIdent `ByteArray.get) $d_data ($d_offset + $(Lean.Syntax.mkNatLit x):num))
201- else
202- `($(Lean.mkIdent `ByteArray.get) $d_data ($d_offset + $(Lean.Syntax.mkNatLit x):num) |>.toInt8)
203- let y ←
204- if unsigned then
205- `($(Lean.mkIdent (Lean.Name.mkStr2 "UInt8" s! "to{ type.getId.getString!} " )) $y)
206- else
207- `($(Lean.mkIdent (Lean.Name.mkStr2 "Int8" s! "to{ type.getId.getString!} " )) $y)
208- let shift := if le then x * 8 else (len - 1 - x) * 8
209- `($y <<< $(Lean.Syntax.mkNatLit shift):num)
210- let combined ←
211- match ts with
212- | [] => unreachable!
213- | [x] => pure x
214- | head :: tail => do
215- tail.foldlM (init := head) fun (x : Lean.Term) y => do
216- `($x ||| $y)
217- let code ← `(command|
218- @[always_inline]
219- scoped instance : Decode $type where
220- get $d:ident :=
221- if h : $d_offset + $newSize:num < $d_data_size then
222- let val := $combined
223- DecodeResult.success val {$d with offset := $d_offset + $(Lean.Syntax.mkNatLit len):num}
224- else
225- DecodeResult.mkEOI d
226- )
227- return code
228-
229- local syntax "prim_unsigned_le " ident num : command
230- local syntax "prim_unsigned_be " ident num : command
231- local syntax "prim_signed_le " ident num : command
232- local syntax "prim_signed_be " ident num : command
233-
234- local macro_rules
235- | `(command| prim_unsigned_le $type $size) => generate_prim true true type size
236- | `(command| prim_unsigned_be $type $size) => generate_prim false true type size
237- | `(command| prim_signed_le $type $size) => generate_prim true false type size
238- | `(command| prim_signed_be $type $size) => generate_prim false false type size
239-
240180public section
241181
242182namespace LE
243183
244- prim_unsigned_le UInt16 2
245- prim_unsigned_le UInt32 4
246- prim_unsigned_le UInt64 8
184+ @[always_inline]
185+ scoped instance : Decode UInt16 where
186+ get d :=
187+ if h : d.offset + 1 < d.data.size then
188+ let val :=
189+ (d.data[d.offset + 0 ]).toUInt16 |||
190+ (d.data[d.offset + 1 ]).toUInt16 <<< 8
191+ DecodeResult.success val {d with offset := d.offset + 2 }
192+ else
193+ DecodeResult.mkEOI d
247194
248- prim_signed_le Int16 2
249- prim_signed_le Int32 4
250- prim_signed_le Int64 8
195+ @[always_inline]
196+ scoped instance : Decode UInt32 where
197+ get d :=
198+ if h : d.offset + 3 < d.data.size then
199+ let val :=
200+ (d.data.get (d.offset + 0 )).toUInt32 |||
201+ (d.data.get (d.offset + 1 )).toUInt32 <<< 8 |||
202+ (d.data.get (d.offset + 2 )).toUInt32 <<< 16 |||
203+ (d.data.get (d.offset + 3 )).toUInt32 <<< 24
204+ DecodeResult.success val {d with offset := d.offset + 4 }
205+ else
206+ DecodeResult.mkEOI d
207+
208+ @[always_inline]
209+ scoped instance : Decode UInt64 where
210+ get d :=
211+ if h : d.offset + 7 < d.data.size then
212+ let val :=
213+ (d.data.get (d.offset + 0 )).toUInt64 |||
214+ (d.data.get (d.offset + 1 )).toUInt64 <<< 8 |||
215+ (d.data.get (d.offset + 2 )).toUInt64 <<< 16 |||
216+ (d.data.get (d.offset + 3 )).toUInt64 <<< 24 |||
217+ (d.data.get (d.offset + 4 )).toUInt64 <<< 32 |||
218+ (d.data.get (d.offset + 5 )).toUInt64 <<< 40 |||
219+ (d.data.get (d.offset + 6 )).toUInt64 <<< 48 |||
220+ (d.data.get (d.offset + 7 )).toUInt64 <<< 56
221+ DecodeResult.success val {d with offset := d.offset + 8 }
222+ else
223+ DecodeResult.mkEOI d
224+
225+ @[always_inline]
226+ scoped instance : Decode Int16 where
227+ get := Int16.ofUInt16 <$> Decode.get (α := UInt16)
228+
229+ @[always_inline]
230+ scoped instance : Decode Int32 where
231+ get := Int32.ofUInt32 <$> Decode.get (α := UInt32)
232+
233+ @[always_inline]
234+ scoped instance : Decode Int64 where
235+ get := Int64.ofUInt64 <$> Decode.get (α := UInt64)
251236
252237@[always_inline]
253238scoped instance : Decode Float32 where
@@ -261,13 +246,58 @@ end LE
261246
262247namespace BE
263248
264- prim_unsigned_be UInt16 2
265- prim_unsigned_be UInt32 4
266- prim_unsigned_be UInt64 8
249+ @[always_inline]
250+ scoped instance : Decode UInt16 where
251+ get d :=
252+ if h : d.offset + 1 < d.data.size then
253+ let val :=
254+ (d.data.get (d.offset + 0 )).toUInt16 <<< 8 |||
255+ (d.data.get (d.offset + 1 )).toUInt16
256+ DecodeResult.success val {d with offset := d.offset + 2 }
257+ else
258+ DecodeResult.mkEOI d
259+
260+ @[always_inline]
261+ scoped instance : Decode UInt32 where
262+ get d :=
263+ if h : d.offset + 3 < d.data.size then
264+ let val :=
265+ (d.data.get (d.offset + 0 )).toUInt32 <<< 24 |||
266+ (d.data.get (d.offset + 1 )).toUInt32 <<< 16 |||
267+ (d.data.get (d.offset + 2 )).toUInt32 <<< 8 |||
268+ (d.data.get (d.offset + 3 )).toUInt32
269+ DecodeResult.success val {d with offset := d.offset + 4 }
270+ else
271+ DecodeResult.mkEOI d
272+
273+ @[always_inline]
274+ scoped instance : Decode UInt64 where
275+ get d :=
276+ if h : d.offset + 7 < d.data.size then
277+ let val :=
278+ (d.data.get (d.offset + 0 )).toUInt64 <<< 56 |||
279+ (d.data.get (d.offset + 1 )).toUInt64 <<< 48 |||
280+ (d.data.get (d.offset + 2 )).toUInt64 <<< 40 |||
281+ (d.data.get (d.offset + 3 )).toUInt64 <<< 32 |||
282+ (d.data.get (d.offset + 4 )).toUInt64 <<< 24 |||
283+ (d.data.get (d.offset + 5 )).toUInt64 <<< 16 |||
284+ (d.data.get (d.offset + 6 )).toUInt64 <<< 8 |||
285+ (d.data.get (d.offset + 7 )).toUInt64
286+ DecodeResult.success val {d with offset := d.offset + 8 }
287+ else
288+ DecodeResult.mkEOI d
267289
268- prim_signed_be Int16 2
269- prim_signed_be Int32 4
270- prim_signed_be Int64 8
290+ @[always_inline]
291+ scoped instance : Decode Int16 where
292+ get := Int16.ofUInt16 <$> Decode.get (α := UInt16)
293+
294+ @[always_inline]
295+ scoped instance : Decode Int32 where
296+ get := Int32.ofUInt32 <$> Decode.get (α := UInt32)
297+
298+ @[always_inline]
299+ scoped instance : Decode Int64 where
300+ get := Int64.ofUInt64 <$> Decode.get (α := UInt64)
271301
272302@[always_inline]
273303scoped instance : Decode Float32 where
0 commit comments