// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use deno_core::error::AnyError; use deno_core::op; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; use deno_core::ZeroCopyBuf; use flate2::write::GzDecoder; use flate2::write::GzEncoder; use flate2::write::ZlibDecoder; use flate2::write::ZlibEncoder; use flate2::Compression; use std::borrow::Cow; use std::cell::RefCell; use std::io::Write; use std::rc::Rc; #[derive(Debug)] struct CompressionResource(RefCell); #[derive(Debug)] enum Inner { DeflateDecoder(ZlibDecoder>), DeflateEncoder(ZlibEncoder>), GzDecoder(GzDecoder>), GzEncoder(GzEncoder>), } impl Resource for CompressionResource { fn name(&self) -> Cow { "compression".into() } } #[op] pub fn op_compression_new( state: &mut OpState, format: String, is_decoder: bool, ) -> Result { let w = Vec::new(); let inner = match (format.as_str(), is_decoder) { ("deflate", true) => Inner::DeflateDecoder(ZlibDecoder::new(w)), ("deflate", false) => { Inner::DeflateEncoder(ZlibEncoder::new(w, Compression::default())) } ("gzip", true) => Inner::GzDecoder(GzDecoder::new(w)), ("gzip", false) => { Inner::GzEncoder(GzEncoder::new(w, Compression::default())) } _ => unreachable!(), }; let resource = CompressionResource(RefCell::new(inner)); Ok(state.resource_table.add(resource)) } #[op] pub fn op_compression_write( state: &mut OpState, rid: ResourceId, input: ZeroCopyBuf, ) -> Result { let resource = state.resource_table.get::(rid)?; let mut inner = resource.0.borrow_mut(); let out: Vec = match &mut *inner { Inner::DeflateDecoder(d) => { d.write_all(&input)?; d.flush()?; d.get_mut().drain(..) } Inner::DeflateEncoder(d) => { d.write_all(&input)?; d.flush()?; d.get_mut().drain(..) } Inner::GzDecoder(d) => { d.write_all(&input)?; d.flush()?; d.get_mut().drain(..) } Inner::GzEncoder(d) => { d.write_all(&input)?; d.flush()?; d.get_mut().drain(..) } } .collect(); Ok(out.into()) } #[op] pub fn op_compression_finish( state: &mut OpState, rid: ResourceId, ) -> Result { let resource = state.resource_table.take::(rid)?; let resource = Rc::try_unwrap(resource).unwrap(); let inner = resource.0.into_inner(); let out: Vec = match inner { Inner::DeflateDecoder(d) => d.finish()?, Inner::DeflateEncoder(d) => d.finish()?, Inner::GzDecoder(d) => d.finish()?, Inner::GzEncoder(d) => d.finish()?, }; Ok(out.into()) }