aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/library/lux/data/binary.lux
blob: 1c0f45a8455fa0bd2f9bb044388fc5df2008c31e (plain)
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
(.require
 [library
  [lux (.except)
   ["[0]" ffi]
   [abstract
    [equivalence (.only Equivalence)]
    [monoid (.only Monoid)]]
   [control
    ["[0]" try (.only Try)]
    ["[0]" exception (.only exception:)]]
   [data
    [text
     ["%" \\format]]
    [collection
     ["[0]" array
      [\\unsafe (.only)]]]]
   [math
    [number
     ["n" nat]]]]]
 ["[0]" /
  ["[1]" \\unsafe]])

(type: .public Binary
  /.Binary)

(def .public size
  (-> Binary Nat)
  (|>> /.size))

(def .public empty
  (-> Nat Binary)
  (|>> /.empty))

(def .public (mix $ init it)
  (All (_ a) (-> (-> I64 a a) a Binary a))
  (let [size (/.size it)]
    (loop (again [index 0
                  output init])
      (if (n.< size index)
        (again (++ index) ($ (/.bits_8 index it) output))
        output))))

(exception: .public (index_out_of_bounds [size Nat
                                          index Nat])
  (exception.report
   "Size" (%.nat size)
   "Index" (%.nat index)))

(with_template [<safe> <unsafe> <shift>]
  [(def .public (<safe> index it)
     (-> Nat Binary (Try I64))
     (if (n.< (/.size it) (|> index <shift>))
       {try.#Success (<unsafe> index it)}
       (exception.except ..index_out_of_bounds [(/.size it) index])))]

  [bits_8 /.bits_8 (|>)]
  [bits_16 /.bits_16 (n.+ 1)]
  [bits_32 /.bits_32 (n.+ 3)]
  [bits_64 /.bits_64 (n.+ 7)]
  )

(with_template [<safe> <unsafe> <shift>]
  [(def .public (<safe> index value it)
     (-> Nat (I64 Any) Binary (Try Binary))
     (if (n.< (/.size it) (|> index <shift>))
       {try.#Success (<unsafe> index value it)}
       (exception.except ..index_out_of_bounds [(/.size it) index])))]

  [has_8! /.has_8! (|>)]
  [has_16! /.has_16! (n.+ 1)]
  [has_32! /.has_32! (n.+ 3)]
  [has_64! /.has_64! (n.+ 7)]
  )

(def .public equivalence
  (Equivalence Binary)
  (implementation
   (def (= reference sample)
     (/.= reference sample))))

(exception: .public (cannot_copy [bytes Nat
                                  source_input Nat
                                  target_output Nat])
  (exception.report
   "Bytes" (%.nat bytes)
   "Source input space" (%.nat source_input)
   "Target output space" (%.nat target_output)))

(def .public (copy! bytes source_offset source target_offset target)
  (-> Nat Nat Binary Nat Binary (Try Binary))
  (let [source_input (n.- source_offset (/.size source))
        target_output (n.- target_offset (/.size target))]
    (if (or (n.< bytes source_input)
            (n.< bytes target_output))
      (exception.except ..cannot_copy [bytes source_input target_output])
      {try.#Success (/.copy! bytes source_offset source target_offset target)})))

(exception: .public (slice_out_of_bounds [size Nat
                                          offset Nat
                                          length Nat])
  (exception.report
   "Size" (%.nat size)
   "Offset" (%.nat offset)
   "Length" (%.nat length)))

(def .public (slice offset length binary)
  (-> Nat Nat Binary (Try Binary))
  (let [size (/.size binary)
        limit (n.+ length offset)]
    (if (n.< limit size)
      (exception.except ..slice_out_of_bounds [size offset length])
      {try.#Success (/.slice offset length binary)})))

(def .public (after bytes binary)
  (-> Nat Binary Binary)
  (cond (n.= 0 bytes)
        binary

        (n.< (/.size binary) bytes)
        (/.slice bytes (n.- bytes (/.size binary)) binary)

        ... else
        (/.empty 0)))

(def .public monoid
  (Monoid Binary)
  (implementation
   (def identity
     (/.empty 0))

   (def (composite left right)
     (let [sizeL (/.size left)
           sizeR (/.size right)
           output (/.empty (n.+ sizeL sizeR))]
       (exec
         (/.copy! sizeL 0 left 0 output)
         (/.copy! sizeR 0 right sizeL output)
         output)))))