wasi-crypto 0.1.15

Experimental implementation of the WASI cryptography APIs
Documentation
use std::collections::HashMap;
use std::sync::Mutex;

use crate::error::*;

pub type Handle = u32;

struct HandlesManagerInner<HandleType: Clone + Sync> {
    last_handle: Handle,
    map: HashMap<Handle, HandleType>,
    type_id: u8,
}

pub(crate) struct HandlesManager<HandleType: Clone + Send + Sync> {
    inner: Mutex<HandlesManagerInner<HandleType>>,
}

impl<HandleType: Clone + Send + Sync> HandlesManager<HandleType> {
    pub fn new(handle_type: u8) -> Self {
        HandlesManager {
            inner: Mutex::new(HandlesManagerInner::new(handle_type)),
        }
    }

    pub fn close(&self, handle: Handle) -> Result<(), CryptoError> {
        self.inner.lock().unwrap().close(handle)
    }

    pub fn register(&self, op: HandleType) -> Result<Handle, CryptoError> {
        self.inner.lock().unwrap().register(op)
    }

    pub fn get(&self, handle: Handle) -> Result<HandleType, CryptoError> {
        self.inner.lock().unwrap().get(handle).cloned()
    }
}

impl<HandleType: Clone + Send + Sync> HandlesManagerInner<HandleType> {
    pub fn new(type_id: u8) -> Self {
        HandlesManagerInner {
            last_handle: (type_id as Handle).rotate_right(8),
            map: HashMap::new(),
            type_id,
        }
    }

    pub fn close(&mut self, handle: Handle) -> Result<(), CryptoError> {
        self.map.remove(&handle).ok_or(CryptoError::Closed)?;
        Ok(())
    }

    fn next_handle(&self, handle: Handle) -> Handle {
        ((handle.wrapping_add(1) << 8) | (self.type_id as Handle)).rotate_right(8)
    }

    pub fn register(&mut self, op: HandleType) -> Result<Handle, CryptoError> {
        let mut handle = self.next_handle(self.last_handle);
        loop {
            if !self.map.contains_key(&handle) {
                break;
            }
            ensure!(handle != self.last_handle, CryptoError::TooManyHandles);
            handle = self.next_handle(handle);
        }
        self.last_handle = handle;
        ensure!(
            self.map.insert(handle, op).is_none(),
            CryptoError::InternalError
        );
        Ok(handle)
    }

    pub fn get(&mut self, handle: Handle) -> Result<&HandleType, CryptoError> {
        let op = self.map.get(&handle).ok_or(CryptoError::InvalidHandle)?;
        Ok(op)
    }
}