Skip to content

Commit 8b55b70

Browse files
committed
[ new ] Bytestrings and builders
1 parent 5139e65 commit 8b55b70

File tree

9 files changed

+283
-2
lines changed

9 files changed

+283
-2
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,16 @@ New modules
184184
Data.Word8.Literals
185185
```
186186

187+
* Bytestrings and builders:
188+
```agda
189+
Data.Bytestring.Base
190+
Data.Bytestring.Builder.Base
191+
Data.Bytestring.Builder.Primitive
192+
Data.Bytestring.IO
193+
Data.Bytestring.IO.Primitive
194+
Data.Bytestring.Primitive
195+
```
196+
187197
Additions to existing modules
188198
-----------------------------
189199

GenerateEverything.hs

+6
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ unsafeModules = map modToFile
4444
, "Codata.Musical.Covec"
4545
, "Codata.Musical.Conversion"
4646
, "Codata.Musical.Stream"
47+
, "Data.Bytestring.Base"
48+
, "Data.Bytestring.Builder.Base"
49+
, "Data.Bytestring.Builder.Primitive"
50+
, "Data.Bytestring.IO"
51+
, "Data.Bytestring.IO.Primitive"
52+
, "Data.Bytestring.Primitive"
4753
, "Debug.Trace"
4854
, "Effect.Monad.IO"
4955
, "Effect.Monad.IO.Instances"

src/Data/Bytestring/Base.agda

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
------------------------------------------------------------------------
2+
-- The Agda standard library
3+
--
4+
-- Bytestrings: simple types and functions
5+
-- Note that these functions do not perform bound checks.
6+
------------------------------------------------------------------------
7+
8+
{-# OPTIONS --cubical-compatible #-}
9+
10+
module Data.Bytestring.Base where
11+
12+
open import Data.Nat.Base using (ℕ; _+_; _*_; _^_)
13+
open import Agda.Builtin.String using (String)
14+
import Data.Fin.Base as Fin
15+
open import Data.Vec.Base as Vec using (Vec)
16+
open import Data.Word8.Base as Word8 using (Word8)
17+
open import Data.Word64.Base as Word64 using (Word64)
18+
19+
open import Function.Base using (const; _$_)
20+
21+
------------------------------------------------------------------------------
22+
-- Re-export type and operations
23+
24+
open import Data.Bytestring.Primitive as Prim public
25+
using ( Bytestring
26+
; length
27+
; take
28+
; drop
29+
)
30+
renaming (index to getWord8)
31+
32+
------------------------------------------------------------------------------
33+
-- Operations
34+
35+
slice : Word64 Word64 Bytestring Bytestring
36+
slice start chunk buf = take chunk (drop start buf)
37+
38+
------------------------------------------------------------------------------
39+
-- Generic combinators for fixed-size encodings
40+
41+
getWord8s : (n : ℕ) Bytestring Word64 Vec Word8 n
42+
getWord8s n buf idx
43+
= let idx = Word64.toℕ idx in
44+
Vec.map (λ k getWord8 buf (Word64.fromℕ (idx + Fin.toℕ k)))
45+
$ Vec.allFin n
46+
47+
-- Little endian representation:
48+
-- Low place values first
49+
fromWord8sLE : {n w} {W : Set w} (fromℕ : W) Vec Word8 n W
50+
fromWord8sLE f ws = f (Vec.foldr′ (λ w acc Word8.toℕ w + acc * (2 ^ 8)) 0 ws)
51+
52+
-- Big endian representation
53+
-- Big place values first
54+
fromWord8sBE : {n w} {W : Set w} (fromℕ : W) Vec Word8 n W
55+
fromWord8sBE f ws = f (Vec.foldl′ (λ acc w acc * (2 ^ 8) + Word8.toℕ w) 0 ws)
56+
57+
------------------------------------------------------------------------------
58+
-- Getting Word64
59+
60+
getWord64LE : Bytestring Word64 Word64
61+
getWord64LE buf idx
62+
= fromWord8sLE Word64.fromℕ (getWord8s 8 buf idx)
63+
64+
getWord64BE : Bytestring Word64 Word64
65+
getWord64BE buf idx
66+
= fromWord8sBE Word64.fromℕ (getWord8s 8 buf idx)

src/Data/Bytestring/Builder/Base.agda

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
------------------------------------------------------------------------
2+
-- The Agda standard library
3+
--
4+
-- Bytestrings: builder type and functions
5+
------------------------------------------------------------------------
6+
7+
{-# OPTIONS --cubical-compatible #-}
8+
9+
module Data.Bytestring.Builder.Base where
10+
11+
open import Data.Nat.Base using (ℕ; zero; suc; _/_; _%_; _^_)
12+
open import Data.Word8.Base as Word8 using (Word8)
13+
open import Data.Word64.Base as Word64 using (Word64)
14+
open import Function.Base using (_∘′_)
15+
16+
------------------------------------------------------------------------------
17+
-- Re-export type and operations
18+
19+
open import Data.Bytestring.Builder.Primitive as Prim public
20+
using ( Builder
21+
; toBytestring
22+
; bytestring
23+
; word8
24+
; empty
25+
; _<>_
26+
)
27+
28+
------------------------------------------------------------------------------
29+
-- High-level combinators
30+
31+
module List where
32+
33+
open import Data.List.Base as List using (List)
34+
35+
concat : List Builder Builder
36+
concat = List.foldr _<>_ empty
37+
38+
module Vec where
39+
40+
open import Data.Vec.Base as Vec using (Vec)
41+
42+
concat : {n} Vec Builder n Builder
43+
concat = Vec.foldr′ _<>_ empty
44+
open Vec
45+
46+
------------------------------------------------------------------------------
47+
-- Generic word-specific combinators
48+
49+
open import Data.Vec.Base as Vec using (Vec; []; _∷_)
50+
51+
wordN : {n} Vec Word8 n Builder
52+
wordN = concat ∘′ Vec.map word8
53+
54+
toWord8sLE : {w} {W : Set w} (n : ℕ) (toℕ : W ℕ) W Vec Word8 n
55+
toWord8sLE n toℕ w = loop (toℕ w) n where
56+
57+
loop : (n : ℕ) Vec Word8 n
58+
loop acc 0 = []
59+
loop acc 1 = Word8.fromℕ acc ∷ []
60+
loop acc (suc n) = Word8.fromℕ (acc % 2 ^ 8) ∷ loop (acc / 2 ^ 8) n
61+
62+
toWord8sBE : {w} {W : Set w} (n : ℕ) (toℕ : W ℕ) W Vec Word8 n
63+
toWord8sBE n toℕ w = Vec.reverse (toWord8sLE n toℕ w)
64+
65+
------------------------------------------------------------------------------
66+
-- Builders for Word64
67+
68+
word64LE : Word64 Builder
69+
word64LE w = wordN (toWord8sLE 8 Word64.toℕ w)
70+
71+
word64BE : Word64 Builder
72+
word64BE w = wordN (toWord8sBE 8 Word64.toℕ w)
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
------------------------------------------------------------------------
2+
-- The Agda standard library
3+
--
4+
-- Primitive Bytestrings: builder type and functions
5+
------------------------------------------------------------------------
6+
7+
{-# OPTIONS --cubical-compatible #-}
8+
9+
module Data.Bytestring.Builder.Primitive where
10+
11+
open import Agda.Builtin.Nat
12+
open import Agda.Builtin.String
13+
14+
open import Data.Word8.Primitive
15+
open import Data.Bytestring.Primitive using (Bytestring)
16+
17+
infixr 6 _<>_
18+
19+
postulate
20+
-- Builder and execution
21+
Builder : Set
22+
toBytestring : Builder Bytestring
23+
24+
-- Assembling a builder
25+
bytestring : Bytestring Builder
26+
word8 : Word8 Builder
27+
empty : Builder
28+
_<>_ : Builder Builder Builder
29+
30+
{-# FOREIGN GHC import qualified Data.ByteString.Builder as Builder #-}
31+
{-# FOREIGN GHC import qualified Data.ByteString.Lazy as Lazy #-}
32+
{-# FOREIGN GHC import qualified Data.Text as T #-}
33+
{-# COMPILE GHC Builder = type Builder.Builder #-}
34+
{-# COMPILE GHC toBytestring = Lazy.toStrict . Builder.toLazyByteString #-}
35+
{-# COMPILE GHC bytestring = Builder.byteString #-}
36+
{-# COMPILE GHC word8 = Builder.word8 #-}
37+
{-# COMPILE GHC empty = mempty #-}
38+
{-# COMPILE GHC _<>_ = mappend #-}

src/Data/Bytestring/IO.agda

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
------------------------------------------------------------------------
2+
-- The Agda standard library
3+
--
4+
-- Bytestrings: IO operations
5+
------------------------------------------------------------------------
6+
7+
{-# OPTIONS --guardedness --cubical-compatible #-}
8+
9+
module Data.Bytestring.IO where
10+
11+
open import Agda.Builtin.String
12+
open import IO using (IO; lift)
13+
open import Data.Bytestring.Base using (Bytestring)
14+
open import Data.Unit.Base using (⊤)
15+
16+
import Data.Bytestring.IO.Primitive as Prim
17+
18+
readFile : String IO Bytestring
19+
readFile fp = lift (Prim.readFile fp)
20+
21+
writeFile : String Bytestring IO ⊤
22+
writeFile fp str = lift (Prim.writeFile fp str)

src/Data/Bytestring/IO/Primitive.agda

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
------------------------------------------------------------------------
2+
-- The Agda standard library
3+
--
4+
-- Primitive Bytestrings: IO operations
5+
------------------------------------------------------------------------
6+
7+
{-# OPTIONS --cubical-compatible #-}
8+
9+
module Data.Bytestring.IO.Primitive where
10+
11+
open import Agda.Builtin.String using (String)
12+
open import Agda.Builtin.Unit using (⊤)
13+
open import IO.Primitive.Core using (IO)
14+
15+
open import Data.Bytestring.Primitive
16+
17+
postulate
18+
readFile : String IO Bytestring
19+
writeFile : String Bytestring IO ⊤
20+
21+
{-# FOREIGN GHC import qualified Data.Text as T #-}
22+
{-# FOREIGN GHC import Data.ByteString #-}
23+
{-# COMPILE GHC readFile = Data.ByteString.readFile . T.unpack #-}
24+
{-# COMPILE GHC writeFile = Data.ByteString.writeFile . T.unpack #-}

src/Data/Bytestring/Primitive.agda

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
------------------------------------------------------------------------
2+
-- The Agda standard library
3+
--
4+
-- Primitive bytestrings: simple bindings to Haskell types and functions
5+
------------------------------------------------------------------------
6+
7+
{-# OPTIONS --cubical-compatible #-}
8+
9+
module Data.Bytestring.Primitive where
10+
11+
open import Agda.Builtin.Nat
12+
open import Agda.Builtin.Word
13+
open import Data.Word8.Primitive
14+
15+
-- NB: the bytestring package uses `Int` as the indexing type which
16+
-- Haskell's base specifies as:
17+
--
18+
-- > A fixed-precision integer type with at least the range
19+
-- > [-2^29 .. 2^29-1]. The exact range for a given implementation
20+
-- > can be determined by using minBound and maxBound from the
21+
-- > Bounded class.
22+
--
23+
-- There is no ergonomic way to encode that in a type-safe manner.
24+
-- For now we use `Word64` with the understanding that using indices
25+
-- greater than 2^29-1 may lead to undefined behaviours...
26+
27+
postulate
28+
Bytestring : Set
29+
index : Bytestring Word64 Word8
30+
length : Bytestring Nat
31+
take : Word64 Bytestring Bytestring
32+
drop : Word64 Bytestring Bytestring
33+
34+
{-# FOREIGN GHC import qualified Data.ByteString as B #-}
35+
{-# COMPILE GHC Bytestring = type B.ByteString #-}
36+
{-# COMPILE GHC index = \ buf idx -> B.index buf (fromIntegral idx) #-}
37+
{-# COMPILE GHC length = \ buf -> fromIntegral (B.length buf) #-}
38+
{-# COMPILE GHC take = B.take . fromIntegral #-}
39+
{-# COMPILE GHC drop = B.drop . fromIntegral #-}

src/Data/Word64/Base.agda

+6-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
module Data.Word64.Base where
1010

1111
open import Level using (zero)
12-
import Data.Nat.Base as ℕ
13-
open import Function.Base using (_on_)
12+
open import Algebra.Core using (Op₂)
13+
open import Data.Nat.Base as ℕ using (ℕ)
14+
open import Function.Base using (_on_; _∘₂′_)
1415
open import Relation.Binary.Core using (Rel)
1516
open import Relation.Binary.PropositionalEquality.Core using (_≡_)
1617

@@ -24,6 +25,9 @@ open import Agda.Builtin.Word public
2425
; primWord64FromNat to fromℕ
2526
)
2627

28+
liftOp₂ : Op₂ ℕ Op₂ Word64
29+
liftOp₂ op = fromℕ ∘₂′ op on toℕ
30+
2731
infix 4 _≈_
2832
_≈_ : Rel Word64 zero
2933
_≈_ = _≡_ on toℕ

0 commit comments

Comments
 (0)