brotli 3.1.1

A brotli compressor and decompressor that with an interface avoiding the rust stdlib. This makes it suitable for embedded devices and kernels. It is designed with a pluggable allocator so that the standard lib's allocator may be employed. The default build also includes a stdlib allocator and stream interface. Disable this with --features=no-stdlib. All included code is safe.
Documentation
use core::mem;
#[cfg(feature="std")]
use std;
use alloc::{SliceWrapper, Allocator};
use enc::BrotliAlloc;
use enc::BrotliEncoderParams;
use core::marker::PhantomData;
use enc::threading::{
  CompressMulti,
  SendAlloc,
  InternalSendAlloc,
  BatchSpawnable,
  BatchSpawnableLite,
  Joinable,
  Owned,
  OwnedRetriever,
  CompressionThreadResult,
  InternalOwned,
  PoisonedThreadError,
  BrotliEncoderThreadError,
};





pub struct SingleThreadedJoinable<T:Send+'static, U:Send+'static> {
  result:Result<T, U>,
}
impl<T:Send+'static, U:Send+'static> Joinable<T, U> for SingleThreadedJoinable<T, U> {
  fn join(self) -> Result<T, U> {
    self.result
  }
}
#[cfg(feature="std")]
pub struct SingleThreadedOwnedRetriever<U:Send+'static>(std::sync::RwLock<U>);
#[cfg(feature="std")]
impl<U:Send+'static> OwnedRetriever<U> for SingleThreadedOwnedRetriever<U> {
  fn view<T, F:FnOnce(&U)-> T>(&self, f:F) -> Result<T, PoisonedThreadError> {
    Ok(f(&*self.0.read().unwrap()))
  }
  fn unwrap(self) -> Result<U,PoisonedThreadError> {Ok(self.0.into_inner().unwrap())}
}
#[cfg(feature="std")]
impl<U:Send+'static> SingleThreadedOwnedRetriever<U> {
    fn new(u:U) -> Self {
        SingleThreadedOwnedRetriever(std::sync::RwLock::new(u))
    }
}

#[cfg(not(feature="std"))]
pub struct SingleThreadedOwnedRetriever<U:Send+'static>(U);
#[cfg(not(feature="std"))]
impl<U:Send+'static> SingleThreadedOwnedRetriever<U> {
    fn new(u:U) -> Self {
        SingleThreadedOwnedRetriever(u)
    }
}
#[cfg(not(feature="std"))]
impl<U:Send+'static> OwnedRetriever<U> for SingleThreadedOwnedRetriever<U> {
  fn view<T, F:FnOnce(&U)->T>(&self, f:F) -> Result<T, PoisonedThreadError> {
    Ok(f(&self.0))
  }
  fn unwrap(self) -> Result<U,PoisonedThreadError> {Ok(self.0)}
}

#[derive(Default)]
pub struct SingleThreadedSpawner{}

impl<T:Send+'static, Alloc:BrotliAlloc+Send+'static, U:Send+'static+Sync> BatchSpawnable<T, Alloc, U> for SingleThreadedSpawner
where <Alloc as Allocator<u8>>::AllocatedMemory:Send+'static {
  type JoinHandle = SingleThreadedJoinable<T, BrotliEncoderThreadError>;
  type FinalJoinHandle = SingleThreadedOwnedRetriever<U>;
    fn batch_spawn<F: Fn(usize, usize, &U, Alloc) -> T+Send+'static+Copy>(
    &mut self,
    input: &mut Owned<U>,
    alloc_per_thread:&mut [SendAlloc<T, Alloc, Self::JoinHandle>],
    f: F,
    ) -> Self::FinalJoinHandle {
      let num_threads = alloc_per_thread.len();
      for (index, work) in alloc_per_thread.iter_mut().enumerate() {
        let alloc = work.replace_with_default();
        let ret = f(index, num_threads, input.view(), alloc);
        *work = SendAlloc(InternalSendAlloc::Join(SingleThreadedJoinable{result:Ok(ret)}));
      }
      SingleThreadedOwnedRetriever::<U>::new(mem::replace(input, Owned(InternalOwned::Borrowed)).unwrap())
    }
}

impl<T:Send+'static,
     Alloc:BrotliAlloc+Send+'static,
     U:Send+'static+Sync>
  BatchSpawnableLite<T, Alloc, U> for SingleThreadedSpawner
  where <Alloc as Allocator<u8>>::AllocatedMemory:Send+'static {
  type JoinHandle = <SingleThreadedSpawner as BatchSpawnable<T, Alloc, U>>::JoinHandle;
  type FinalJoinHandle = <SingleThreadedSpawner as BatchSpawnable<T, Alloc, U>>::FinalJoinHandle;
  fn batch_spawn(
    &mut self,
    input: &mut Owned<U>,
    alloc_per_thread:&mut [SendAlloc<T, Alloc, Self::JoinHandle>],
    f: fn(usize, usize, &U, Alloc) -> T,
  ) -> Self::FinalJoinHandle {
   <Self as BatchSpawnable<T, Alloc, U>>::batch_spawn(self, input, alloc_per_thread, f)
  }
}


pub fn compress_multi<Alloc:BrotliAlloc+Send+'static,
                      SliceW: SliceWrapper<u8>+Send+'static+Sync> (
  params:&BrotliEncoderParams,
  owned_input: &mut Owned<SliceW>,
  output: &mut [u8],
  alloc_per_thread:&mut [SendAlloc<CompressionThreadResult<Alloc>,
                                   Alloc,
                                   <SingleThreadedSpawner as BatchSpawnable<CompressionThreadResult<Alloc>,Alloc, SliceW>>::JoinHandle>],
) -> Result<usize, BrotliEncoderThreadError> where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  CompressMulti(params, owned_input, output, alloc_per_thread, &mut SingleThreadedSpawner::default())
}

pub struct WorkerPool<A,B,C> {
  a: PhantomData<A>,
  b: PhantomData<B>,
  c: PhantomData<C>,
}
pub fn new_work_pool<A,B, C>(_num_threads: usize) -> WorkerPool<A, B, C>{
  WorkerPool::<A,B,C>{
    a:PhantomData::default(),
    b:PhantomData::default(),
    c:PhantomData::default(),
  }
}

pub fn compress_worker_pool<Alloc:BrotliAlloc+Send+'static,
                      SliceW: SliceWrapper<u8>+Send+'static+Sync> (
  params:&BrotliEncoderParams,
  owned_input: &mut Owned<SliceW>,
  output: &mut [u8],
  alloc_per_thread:&mut [SendAlloc<CompressionThreadResult<Alloc>,
                                   Alloc,
                                   <SingleThreadedSpawner as BatchSpawnable<CompressionThreadResult<Alloc>,Alloc, SliceW>>::JoinHandle>],
  _worker_pool:&mut WorkerPool<CompressionThreadResult<Alloc>, Alloc, (SliceW, BrotliEncoderParams)>,
) -> Result<usize, BrotliEncoderThreadError> where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  compress_multi(params, owned_input, output, alloc_per_thread)
}