From 94406fe88d938c80e0b75ae86a7c3a909fc34227 Mon Sep 17 00:00:00 2001 From: hellerve Date: Sat, 25 Jan 2020 12:21:01 +0100 Subject: [PATCH] initial --- README.md | 35 +++++++++- docs/ZLib.html | 172 ++++++++++++++++++++++++++++++++++++++++++++++++ docs/style.css | 110 +++++++++++++++++++++++++++++++ gendocs.carp | 13 ++++ tests/zlib.carp | 6 +- zlib.carp | 67 ++++++++++++++++++- zlib_helper.h | 6 +- 7 files changed, 401 insertions(+), 8 deletions(-) create mode 100644 docs/ZLib.html create mode 100644 docs/style.css create mode 100644 gendocs.carp diff --git a/README.md b/README.md index 7fc8481..8e00b50 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,39 @@ is a high-level wrapper around [zlib](https://zlib.net/). +## Installation + +```clojure +(load "https://veitheller.de/git/carpentry/zlib.git@0.0.1") +``` + ## Usage -The `ZLib` module provides only two functions +The `ZLib` module provides only two functions, `inflate` and `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 `deflate-with`. The +levels are defined in `ZLib.ZLevel`, and are `NoCompression`, `BestSpeed`, +`BestCompression`, and `DefaultCompression`, which is, well, the default. + +
+ +Have fun! diff --git a/docs/ZLib.html b/docs/ZLib.html new file mode 100644 index 0000000..32c55ea --- /dev/null +++ b/docs/ZLib.html @@ -0,0 +1,172 @@ + + + + + + + + + +
+ +

+ ZLib +

+
+

is a high-level wrapper around zlib.

+

Installation

+
(load "https://veitheller.de/git/carpentry/zlib.git@0.0.1")
+
+

Usage

+

The ZLib module provides only two functions, inflate and +deflate. These functions work in tandem to provide you with data +compression.

+
; 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.

+
(=> (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, and are NoCompression, +BestSpeed, BestCompression, and DefaultCompression, which is, well, the +default.

+ +
+
+ +

+ ZBytes +

+
+
+ module +
+

+ Module +

+ + + +

+ +

+
+
+ +

+ ZLevel +

+
+
+ module +
+

+ Module +

+ + + +

+

is a type used in conjunction with +deflate-with. It controls the compression level.

+

The constructors are NoCompression, BestSpeed, BestCompression, and +DefaultCompression, which is, well, the default.

+ +

+
+
+ +

+ deflate +

+
+
+ defn +
+

+ (λ [&String] (Result ZBytes String)) +

+
+                    (deflate s)
+                
+

+

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 with +(ZLevel.DefaultCompression).

+ +

+
+
+ +

+ deflate-with +

+
+
+ defn +
+

+ (λ [&String, ZLevel] (Result ZBytes String)) +

+
+                    (deflate-with s level)
+                
+

+

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.

+ +

+
+
+ +

+ inflate +

+
+
+ defn +
+

+ (λ [ZBytes] (Result String String)) +

+
+                    (inflate s)
+                
+

+

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.

+ +

+
+
+ + diff --git a/docs/style.css b/docs/style.css new file mode 100644 index 0000000..ed4f963 --- /dev/null +++ b/docs/style.css @@ -0,0 +1,110 @@ +html { + font-family: "Helvetica", sans-serif; + font-size: 16px; +} + +a { + color: #000; +} + +.logo { + display: none; +} + +ul { + list-style-type: none; + font-family: "Hasklig", "Lucida Console", monospace; + line-height: 1.4em; +} + +.module-description { + margin-bottom: 3em; +} + +.content { + margin: 3em auto auto auto; + width: 80%; + max-width: 610px; + min-width: 400px +} + +h1 { + margin-bottom: 1em; + font-weight: 400; +} + +h2 { + font-weight: 400; + margin-bottom: 0em; +} + +h3 { + margin: 0em; + font-weight: 400; +} + +.binder { + margin: 0em 0em 3.5em 0em; +} + +.sig { + font-family: "Hasklig", "Lucida Console", monospace; + margin: 0.5em 0em 0.5em 0em; +} + +.args { + background-color: #eee; + display: inline-block; + white-space: normal; + margin: 0; + margin-bottom: 1em; +} + +code { + background-color: #eee; +} + +pre { + background-color: #eee; + overflow-y: scroll; +} + +.description { + margin-top: 0.3em; + font-size: 0.8em; + color: #aaa; +} + +.huge { + font-size: 15em; + margin: 0em; +} + +/* Smaller screens */ +@media only screen and (max-width: 600px) { + .logo { + margin: 1em; + text-align: left; + float: left; + width: 100%; + } + .logo img { + display: block; + margin-left: auto; + margin-right: auto; + width: 50%; + } + .content { + margin: 0.5em; + } + .binder { + margin: 0em 0em 1.5em 0em; + } + .sig { + font-size: 0.9em; + } + ul { + padding: 0px; + } +} +.title, .index { display: none; } diff --git a/gendocs.carp b/gendocs.carp new file mode 100644 index 0000000..d8d0c45 --- /dev/null +++ b/gendocs.carp @@ -0,0 +1,13 @@ +(load "zlib.carp") + +(defndynamic gendocs [] + (do + (Project.config "title" "zlib") + (Project.config "docs-directory" "./docs/") + (Project.config "docs-logo" "") + (Project.config "docs-styling" "style.css") + (Project.config "docs-generate-index" false) + (save-docs ZLib))) + +(gendocs) +(quit) diff --git a/tests/zlib.carp b/tests/zlib.carp index c75d373..2438147 100644 --- a/tests/zlib.carp +++ b/tests/zlib.carp @@ -6,11 +6,11 @@ (deftest test (assert-true test - (Result.success? &(deflate @"hi")) + (Result.success? &(deflate "hi")) "deflation returns success" ) (assert-true test - (Result.success? &(inflate (Result.unsafe-from-success (deflate @"hi")))) + (Result.success? &(inflate (Result.unsafe-from-success (deflate "hi")))) "deflation->inflation returns success" ) (assert-equal test @@ -20,7 +20,7 @@ ) (assert-equal test &(Result.Success @"hi") - &(inflate (Result.unsafe-from-success (deflate @"hi"))) + &(inflate (Result.unsafe-from-success (deflate "hi"))) "deflation->inflation works" ) ) diff --git a/zlib.carp b/zlib.carp index e21d39e..d968515 100644 --- a/zlib.carp +++ b/zlib.carp @@ -1,14 +1,54 @@ (relative-include "zlib_helper.h") (add-cflag "-lz") + +(doc ZLib "is a high-level wrapper around [zlib](https://zlib.net/). + +## Installation + +```clojure +(load \"https://veitheller.de/git/carpentry/zlib.git@0.0.1\") +``` + +## 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 + (doc ZBytes "is an opaque bytes type with an associated length.") (register-type ZBytes [ len Int bytes String ]) + (private ZRes) + (hidden ZRes) (register-type ZRes) (defmodule ZRes (register ok? (Fn [&ZRes] Bool) "ZRes_is_ok") @@ -17,6 +57,11 @@ (register err (Fn [ZRes] String) "ZRes_err") ) + (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.") (deftype ZLevel (NoCompression []) (BestSpeed []) @@ -32,19 +77,39 @@ (BestCompression) 9 (DefaultCompression) -1))) + (private inflate-) + (hidden inflate-) (register inflate- (Fn [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))))) - (register deflate- (Fn [String Int] ZRes) "ZLib_deflate_c") + (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))) ) diff --git a/zlib_helper.h b/zlib_helper.h index 09a6b48..a51c7c0 100644 --- a/zlib_helper.h +++ b/zlib_helper.h @@ -134,7 +134,7 @@ err: return res; } -ZRes ZLib_deflate_c(char* s, int level) { +ZRes ZLib_deflate_c(String* s, int level) { int ret, flush; unsigned have; z_stream strm; @@ -142,7 +142,7 @@ ZRes ZLib_deflate_c(char* s, int level) { unsigned char in[CHUNK]; unsigned char out[CHUNK]; int offs = 0; - int len = strlen(s); + int len = strlen(*s); ZBytes* bytes = malloc(sizeof(ZBytes)); bytes->bytes = NULL; bytes->len = 0; @@ -158,7 +158,7 @@ ZRes ZLib_deflate_c(char* s, int level) { do { strm.avail_in = min(CHUNK, len-offs); if (strm.avail_in <= 0) break; - memcpy(in, s+offs, strm.avail_in); + memcpy(in, (*s)+offs, strm.avail_in); offs += strm.avail_in; flush = offs >= len-1 ? Z_FINISH : Z_NO_FLUSH; strm.next_in = in;