cde 0.3.7

A universal encoding scheme for all cryptographic data
Documentation
use anyhow;
use data_encoding::Encoding;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum Error {
    #[error("general error")]
    GeneralError,
    #[error("io error")]
    IoError(#[from] std::io::Error),
    #[error("fmt error")]
    FmtError(#[from] std::fmt::Error),
    #[error("invalid class")]
    InvalidClass,
    #[error("invalid sub-class")]
    InvalidSubClass,
    #[error("invalid sub-sub-class value")]
    InvalidSubSubClass,
    #[error("numerical type value out of range (>=64)")]
    InvalidTypeNumber(u8),
    #[error("type name begins with invalid letter not in [a-zA-Z0-9-_]")]
    InvalidTypeFirstLetter,
    #[error("parent type is non-experimental")]
    NonExperimentalParentType(u8),
    #[error("invalid non-ascii type name")]
    InvalidTypeName,
    #[error("failed to build from str")]
    FromStr,
    #[error("failed to build from bytes")]
    FromBytes,
    #[error("no buffer given")]
    MissingBuf,
    #[error("decode error")]
    DecodeError,
    #[error("invalid length")]
    InvalidLength,
}

pub type Result<T> = anyhow::Result<T, Error>;

pub static CDE_ALPHABET: &'static str =
    "abcdefghijklmnopqrstuvwxyz01234-ABCDEFGHIJKLMNOPQRSTUVWXYZ56789_";
pub static ENCODER: Encoding = data_encoding_macro::new_encoding! {
    symbols: "abcdefghijklmnopqrstuvwxyz01234-ABCDEFGHIJKLMNOPQRSTUVWXYZ56789_",
};

pub fn idx(c: char) -> u8 {
    if let Some(i) = CDE_ALPHABET.find(c) {
        i as u8
    } else {
        63
    }
}

pub fn ch(i: u8) -> char {
    if i < 64 {
        CDE_ALPHABET.as_bytes()[i as usize] as char
    } else {
        '_'
    }
}

pub fn decode_tag_and_data<'a, T: From<&'a [u8]>>(
    encoded: &[u8],
    buf: &'a mut [u8],
) -> Result<(Tag, T)> {
    let len = ENCODER
        .decode_len(encoded.len())
        .map_err(|_| Error::DecodeError)?;
    ENCODER
        .decode_mut(encoded, &mut buf[0..len])
        .map_err(|_| Error::DecodeError)?;
    let tag = TagBuilder::from_bytes(&buf).build()?;
    let len = tag.len();
    let data_len = tag.get_data_length();
    let data = T::from(&buf[len..len + data_len]);
    Ok((tag, data))
}

pub fn encode_tag_and_data<'a>(
    tag: &mut Tag,
    data: &impl CryptoData,
    buf: &'a mut [u8],
) -> Result<usize> {
    tag.set_data_length(data.len());
    let tagsize = tag.encode(buf);
    let datasize = data.encode(&mut buf[tagsize..]);
    Ok(tagsize + datasize)
}

pub trait CryptoData {
    fn len(&self) -> usize;
    fn bytes(&self, buf: &mut [u8]) -> usize;
    fn encode_len(&self) -> usize;
    fn encode(&self, buf: &mut [u8]) -> usize;
}

mod tag;
pub use tag::*;
mod varuint;
pub use varuint::*;