-
Notifications
You must be signed in to change notification settings - Fork 0
/
zlib.carp
114 lines (93 loc) · 3.44 KB
/
zlib.carp
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
(relative-include "zlib_helper.h")
(add-cflag "-lz")
(doc ZLib "is a high-level wrapper around [zlib](https://zlib.net/).
## Installation
```clojure
(load \"git@git.veitheller.de:carpentry/zlib.git@0.0.2\")
```
## Usage
The `ZLib` module provides only two functions, [`inflate`](#inflate) and
[`deflate`](#deflate). These functions work in tandem to provide you with data
compression.
```clojure
; deflate returns a Result of either binary data or an error message
(let [deflated (ZLib.deflate \"mystring\")]
(match deflated
; inflate returns a Result of either a string or an error message
(Success bin) (println* &(inflate bin))
(Error msg) (IO.errorln &msg)))
```
Because it’s a `Result` type, we can apply combinators to it.
```clojure
(=> (ZLib.deflate \"mystring\")
(Result.and-then &ZLib.inflate)
(Result.map-error &(fn [msg] (do (println* &msg) msg)))
)
```
You can also choose different levels of compression using `inflate-with`. The
levels are defined in [`ZLib.ZLevel`](#ZLevel), and are `NoCompression`,
`BestSpeed`, `BestCompression`, and `DefaultCompression`, which is, well, the
default.")
; i tried doing this in carp, but it’s a bit of a pain to wrap the API
; idiomatically, so for now you’ll only get regular inflation and deflation
(defmodule ZLib
(register-type ZBytes [
len Int
bytes String
])
(hidden ZBytes)
(register-type ZRes)
(defmodule ZRes
(register ok? (Fn [&ZRes] Bool) "ZRes_is_ok")
(register bytes (Fn [ZRes] ZLib.ZBytes) "ZRes_bytes")
(register str (Fn [ZRes] String) "ZRes_str")
(register err (Fn [ZRes] String) "ZRes_err")
)
(hidden ZRes)
(deftype ZLevel
(NoCompression [])
(BestSpeed [])
(BestCompression [])
(DefaultCompression [])
)
(defmodule ZLevel
(defn to-int [l]
(match l
(NoCompression) 0
(BestSpeed) 1
(BestCompression) 9
(DefaultCompression) -1)))
(doc ZLevel "is a type used in conjunction with
[`deflate-with`](#deflate-with). It controls the compression level.
The constructors are `NoCompression`, `BestSpeed`, `BestCompression`, and
`DefaultCompression`, which is, well, the default.")
(private inflate-)
(hidden inflate-)
(register inflate- (Fn [ZLib.ZBytes] ZRes) "ZLib_inflate_c")
(doc inflate "takes a bytes object `s` and returns a `Result`.
The `Result` will be a `Success` containing the inflated string if all goes
well, and an `Error` returning an error message otherwise.")
(defn inflate [s]
(let [r (inflate- s)]
(if (ZRes.ok? &r)
(Result.Success (ZRes.str r))
(Result.Error (ZRes.err r)))))
(private deflate-)
(hidden deflate-)
(register deflate- (Fn [&String Int] ZRes) "ZLib_deflate_c")
(doc deflate-with "takes a bytes object `s`, a `Zlevel` `level` and returns
a `Result`.
The `Result` will be a `Success` containing the deflated bytes if all goes
well, and an `Error` returning an error message otherwise.")
(defn deflate-with [s level]
(let [r (deflate- s (ZLevel.to-int level))]
(if (ZRes.ok? &r)
(Result.Success (ZRes.bytes r))
(Result.Error (ZRes.err r)))))
(doc deflate "takes a bytes object `s` and returns a `Result`.
The `Result` will be a `Success` containing the deflated bytes if all goes
well, and an `Error` returning an error message otherwise.
It is equivalent to calling [`deflate-with`](#deflate-with) with
`(ZLevel.DefaultCompression)`.")
(defn deflate [s] (deflate-with s (ZLevel.DefaultCompression)))
)