Browse Source

Update Rust; fix #15

Arjun Barrett 4 years ago
parent
commit
a6e95a22cc
9 changed files with 170 additions and 100 deletions
  1. 2 2
      .gitignore
  2. 1 1
      package.json
  3. 0 15
      rs/Cargo.toml
  4. 19 0
      rs/fflate-wasm/Cargo.toml
  5. 16 0
      rs/fflate-wasm/src/lib.rs
  6. 33 0
      rs/fflate/Cargo.toml
  7. 97 42
      rs/fflate/src/lib.rs
  8. 0 38
      rs/src/main.rs
  9. 2 2
      src/index.ts

+ 2 - 2
.gitignore

@@ -3,8 +3,8 @@ lib/
 esm/
 .DS_STORE
 # Rust version - available when ready
-rs/target/
-rs/Cargo.lock
+rs/*/target/
+rs/*/Cargo.lock
 
 .DS_STORE
 umd/

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "fflate",
-  "version": "0.4.0",
+  "version": "0.4.1",
   "description": "High performance (de)compression in an 8kB package",
   "main": "./lib/index.js",
   "module": "./esm/index.mjs",

+ 0 - 15
rs/Cargo.toml

@@ -1,15 +0,0 @@
-[package]
-name = "fflate"
-version = "0.0.1"
-authors = ["Arjun Barrett <[email protected]>"]
-edition = "2018"
-
-[dependencies]
-lazy_static = "^1.4.0"
-
-[profile.release]
-opt-level = "s"
-lto = true
-
-[lib]
-crate-type = ["cdylib", "rlib"]

+ 19 - 0
rs/fflate-wasm/Cargo.toml

@@ -0,0 +1,19 @@
+[package]
+name = "fflate-wasm"
+version = "0.0.1"
+authors = ["Arjun Barrett <[email protected]>"]
+edition = "2018"
+
+[dependencies]
+fflate = { path = "../fflate", features = ["std"] }
+wasm-bindgen = "0.2"
+
+[profile.release]
+opt-level = "s"
+lto = true
+
+[package.metadata.wasm-pack.profile.release]
+wasm-opt = ["-Oz", "--enable-mutable-globals"]
+
+[lib]
+crate-type = ["cdylib", "rlib"]

+ 16 - 0
rs/fflate-wasm/src/lib.rs

@@ -0,0 +1,16 @@
+use wasm_bindgen::prelude::*;
+use fflate::{inflate, InflateError};
+
+#[wasm_bindgen]
+pub fn inflate_raw(buf: &[u8]) -> Result<Vec<u8>, JsValue> {
+    let mut out = Vec::new();
+    if let Err(e) = inflate(buf, &mut out) {
+        return Err(JsValue::from(match e {
+            InflateError::InvalidBlockType => "invalid block type",
+            InflateError::InvalidDistance => "invalid distance",
+            InflateError::InvalidLengthOrLiteral => "invalid length/literal",
+            InflateError::UnexpectedEOF => "unexpected EOF"
+        }));
+    }
+    Ok(out)
+}

+ 33 - 0
rs/fflate/Cargo.toml

@@ -0,0 +1,33 @@
+[package]
+name = "fflate"
+version = "0.0.1"
+authors = ["Arjun Barrett <[email protected]>"]
+description = "A fast, efficient, pure Rust compression library"
+repository = "https://github.com/101arrowz/fflate"
+license = "MIT"
+keywords = [
+  "compression",
+  "decompression",
+  "deflate",
+  "inflate",
+  "gzip",
+  "gunzip",
+  "zlib",
+  "zip",
+  "libflate",
+  "flate2"
+]
+edition = "2018"
+
+[dependencies]
+lazy_static = "1.4"
+
+[profile.release]
+opt-level = "s"
+lto = true
+
+[features]
+std = []
+
+[lib]
+crate-type = ["cdylib", "rlib"]

+ 97 - 42
rs/src/lib.rs → rs/fflate/src/lib.rs

@@ -5,12 +5,12 @@
 // Instead of trying to read this code, check out the TypeScript version
 
 #![allow(non_upper_case_globals)]
-
-extern crate alloc;
-
-use alloc::vec::Vec;
+#![cfg_attr(not(feature = "std"), no_std)]
 use lazy_static::lazy_static;
 
+#[cfg(feature = "std")]
+use std::{vec::Vec, io::{Read, Write, Error, ErrorKind}};
+
 const fleb: [usize; 32] = [
     0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0, 0,
 ];
@@ -49,6 +49,8 @@ const clim: [usize; 19] = [
     16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
 ];
 
+const et: [u8; 0] = [];
+
 fn freb(b: &[u16], r: &mut [u32]) {
     for i in 1..30 {
         let base = b[i];
@@ -91,6 +93,7 @@ fn hrmap(cd: &[u8], mb: u8, co: &mut [u16], le: &mut [u16]) {
     let mbu = mb as usize;
     for i in 0..cd.len() {
         let cl = cd[i] as usize;
+        // TODO: remove cond
         if cl != 0 {
             let r = mbu - cl;
             let v = (le[cl] << r) as usize;
@@ -182,11 +185,12 @@ fn shft(pos: usize) -> usize {
     (pos >> 3) + (pos & 7 != 0) as usize
 }
 
-struct InflateState<'a> {
-    lmap: &'a mut [u16],
-    dmap: &'a mut [u16],
-    clmap: &'a mut [u16],
-    le: &'a mut [u16],
+
+struct InflateState {
+    lmap: [u16; 32768],
+    dmap: [u16; 32768],
+    clmap: [u16; 128],
+    le: [u16; 16],
     lbits: u8,
     dbits: u8,
     bfinal: bool,
@@ -195,7 +199,30 @@ struct InflateState<'a> {
     head: bool,
 }
 
-#[derive(Debug)]
+impl InflateState {
+    #[inline(always)]
+    pub fn new() -> Self {
+        Default::default()
+    }
+}
+
+impl Default for InflateState {
+    fn default() -> Self {
+        InflateState {
+            lmap: [0; 32768],
+            dmap: [0; 32768],
+            clmap: [0; 128],
+            le: [0; 16],
+            lbits: 0,
+            dbits: 0,
+            bfinal: false,
+            pos: 0,
+            last: false,
+            head: true
+        }
+    }
+}
+
 pub enum InflateError {
     UnexpectedEOF,
     InvalidBlockType,
@@ -204,31 +231,32 @@ pub enum InflateError {
 }
 
 pub trait OutputBuffer {
-    fn w(self: &mut Self, value: u8);
-    fn wall(self: &mut Self, slice: &[u8]) {
+    fn w(&mut self, value: u8);
+    fn wall(&mut self, slice: &[u8]) {
         for &value in slice {
             self.w(value);
         }
     }
-    fn palloc(self: &mut Self, extra_bytes: usize);
-    fn back(self: &Self, back: usize) -> u8;
+    fn palloc(&mut self, extra_bytes: usize);
+    fn back(&self, back: usize) -> u8;
 }
 
+#[cfg(feature = "std")]
 impl OutputBuffer for Vec<u8> {
     #[inline(always)]
-    fn w(self: &mut Self, value: u8) {
+    fn w(&mut self, value: u8) {
         self.push(value);
     }
     #[inline(always)]
-    fn wall(self: &mut Self, slice: &[u8]) {
+    fn wall(&mut self, slice: &[u8]) {
         self.extend(slice.iter());
     }
     #[inline(always)]
-    fn palloc(self: &mut Self, extra_bytes: usize) {
+    fn palloc(&mut self, extra_bytes: usize) {
         self.reserve(extra_bytes);
     }
     #[inline(always)]
-    fn back(self: &Self, back: usize) -> u8 {
+    fn back(&self, back: usize) -> u8 {
         self[self.len() - back]
     }
 }
@@ -250,14 +278,14 @@ impl<'a> SliceOutputBuffer<'a> {
 
 impl<'a> OutputBuffer for SliceOutputBuffer<'a> {
     #[inline(always)]
-    fn w(self: &mut Self, value: u8) {
+    fn w(&mut self, value: u8) {
         if self.byte < self.buf.len() {
             self.buf[self.byte] = value;
         }
         self.byte += 1;
     }
     #[inline(always)]
-    fn wall(self: &mut Self, slice: &[u8]) {
+    fn wall(&mut self, slice: &[u8]) {
         let sl = slice.len();
         let end = self.byte + sl;
         if end <= self.buf.len() {
@@ -266,9 +294,9 @@ impl<'a> OutputBuffer for SliceOutputBuffer<'a> {
         self.byte = end;
     }
     #[inline(always)]
-    fn palloc(self: &mut Self, _eb: usize) {}
+    fn palloc(&mut self, _eb: usize) {}
     #[inline(always)]
-    fn back(self: &Self, back: usize) -> u8 {
+    fn back(&self, back: usize) -> u8 {
         self.buf[self.byte - back]
     }
 }
@@ -322,7 +350,7 @@ fn inflt(dat: &[u8], buf: &mut dyn OutputBuffer, st: &mut InflateState) -> Resul
                     if !st.last && pos + tl * (clb + 7) as usize > tbts {
                         break;
                     }
-                    hrmap(&clt, clb, st.clmap, st.le);
+                    hrmap(&clt, clb, &mut st.clmap, &mut st.le);
                     let mut i = 0;
                     loop {
                         let r = st.clmap[bits(dat, pos, clbmsk) as usize];
@@ -362,8 +390,8 @@ fn inflt(dat: &[u8], buf: &mut dyn OutputBuffer, st: &mut InflateState) -> Resul
                     let dt = &ldt[hlit..tl];
                     st.lbits = *lt.iter().max().unwrap();
                     st.dbits = *dt.iter().max().unwrap();
-                    hrmap(lt, st.lbits, st.lmap, st.le);
-                    hrmap(dt, st.dbits, st.dmap, st.le);
+                    hrmap(lt, st.lbits, &mut st.lmap, &mut st.le);
+                    hrmap(dt, st.dbits, &mut st.dmap, &mut st.le);
                 }
                 _ => {
                     return Err(InflateError::InvalidBlockType);
@@ -431,22 +459,49 @@ fn inflt(dat: &[u8], buf: &mut dyn OutputBuffer, st: &mut InflateState) -> Resul
 
 pub fn inflate(dat: &[u8], out: &mut dyn OutputBuffer) -> Result<(), InflateError> {
     out.palloc(dat.len() * 3);
-    let mut buf = [0u16; 65680];
-    let (mut lmap, buf) = buf.split_at_mut(32768);
-    let (mut dmap, buf) = buf.split_at_mut(32768);
-    let (mut clmap, mut le) = buf.split_at_mut(128);
-    let mut st = InflateState {
-        lmap: &mut lmap,
-        dmap: &mut dmap,
-        clmap: &mut clmap,
-        le: &mut le,
-        lbits: 0,
-        dbits: 0,
-        bfinal: false,
-        pos: 0,
-        last: true,
-        head: true
-    };
+    let mut st = InflateState::new();
+    st.last = true;
     inflt(dat, out, &mut st)?;
     Ok(())
-}
+}
+
+pub struct Inflate<'a> {
+    pub sink: &'a mut dyn OutputBuffer,
+    state: InflateState
+}
+
+impl<'a> Inflate<'a> {
+    pub fn push(&mut self, data: &[u8]) -> Result<usize, InflateError> {
+        inflt(data, self.sink, &mut self.state)?;
+        let bytes = self.state.pos >> 3;
+        self.state.pos &= 7;
+        Ok(bytes)
+    }
+    pub fn end(&mut self) -> Result<(), InflateError> {
+        self.state.last = true;
+        self.push(&et)?;
+        Ok(())
+    }
+    pub fn new(sink: &'a mut dyn OutputBuffer) -> Inflate<'a> {
+        Inflate {
+            state: InflateState::new(),
+            sink: sink
+        }
+    }
+}
+
+// #[cfg(feature = "std")]
+// impl<'a> Write for Inflate<'a> {
+//     #[inline(always)]
+//     fn write(&mut self, data: &[u8]) -> Result<usize, Error> {
+//         self.push(data)
+//     }
+//     #[inline(always)]
+//     fn flush(&mut self) -> Result<(), Error> {
+//         match self.end() {
+//             Err(InflateError::UnexpectedEOF) => Err(Error::new(ErrorKind::UnexpectedEof, InflateError::UnexpectedEOF)),
+//             Err(e) => Err(Error::new(ErrorKind::Other, &e)),
+//             Ok(()) => Ok(())
+//         }
+//     }
+// }

+ 0 - 38
rs/src/main.rs

@@ -1,38 +0,0 @@
-use std::fs::{File};
-use std::io::Read;
-use std::vec::Vec;
-use std::time::Instant;
-use std::env::args;
-// use flate2::bufread::DeflateDecoder;
-mod lib;
-
-fn main() {
-    let args: Vec<String> = args().collect();
-    // Assumes run in root dir - good enough for a test
-    let fp_base = String::from("./test");
-    let fp = &args.get(1).unwrap_or(&fp_base);
-    let mut f = File::open(fp).unwrap();
-    let mut v: Vec<u8> = Vec::new();
-    if f.read_to_end(&mut v).is_ok() {
-        for _ in 0..5 {
-            let now = Instant::now();
-            let mut buf = Vec::with_capacity(52344054);
-            unsafe { buf.set_len(52344054); }
-            let mut out = lib::SliceOutputBuffer::new(&mut buf);
-            if let Ok(()) = lib::inflate(&v, &mut out) {
-                let el = now.elapsed();
-                println!("{}.{:06}s {:?}", el.as_secs(), el.as_nanos() / 1000, buf.len());
-            };
-        }
-        // for _ in 0..5 {
-        //     let now = Instant::now();
-        //     let mut out = Vec::new();
-        //     let mut strm = DeflateDecoder::new(&v[..]);
-        //     if let Err(e) = strm.read_to_end(&mut out) {
-        //         panic!(e);
-        //     }
-        //     let el = now.elapsed();
-        //     println!("flate2: {}.{:06}s {:?}", el.as_secs(), el.as_nanos() / 1000, out.len());
-        // }
-    }
-}

+ 2 - 2
src/index.ts

@@ -2142,11 +2142,11 @@ export function zip(data: AsyncZippable, opts: AsyncZipOptions | FlateCallback,
     if (!t) cbl(null, file);
     else if (m < 160000) {
       try {
-        cbl(null, deflateSync(file, opts as AsyncZipOptions));
+        cbl(null, deflateSync(file, p));
       } catch(e) {
         cbl(e, null);
       }
-    } else term.push(deflate(file, opts as AsyncZipOptions, cbl));
+    } else term.push(deflate(file, p, cbl));
   }
   return tAll;
 }