gcrypt 0.5.3

Libgcrypt bindings for Rust
Documentation
use std::fmt;
use std::ptr;
use std::result;
use std::slice;
use std::str::{self, FromStr, Utf8Error};

use libc::c_int;
use ffi;

use {Error, NonZero, Result};
use mpi::Integer;
use mpi::integer::Format as IntegerFormat;

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Format {
    Default = ffi::GCRYSEXP_FMT_DEFAULT as isize,
    Canonical = ffi::GCRYSEXP_FMT_CANON as isize,
    Base64 = ffi::GCRYSEXP_FMT_BASE64 as isize,
    Advanced = ffi::GCRYSEXP_FMT_ADVANCED as isize,
}

pub struct SExpression(NonZero<ffi::gcry_sexp_t>);

impl Drop for SExpression {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            ffi::gcry_sexp_release(self.as_raw());
        }
    }
}

impl SExpression {
    impl_wrapper!(SExpression: ffi::gcry_sexp_t);

    #[inline]
    pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<SExpression> {
        let bytes = bytes.as_ref();
        let _ = ::get_token();
        unsafe {
            let mut result: ffi::gcry_sexp_t = ptr::null_mut();
            return_err!(ffi::gcry_sexp_sscan(
                &mut result,
                ptr::null_mut(),
                bytes.as_ptr() as *const _,
                bytes.len()
            ));
            Ok(SExpression::from_raw(result))
        }
    }

    #[inline]
    pub fn to_bytes(&self, format: Format) -> Vec<u8> {
        let mut buffer = vec![0; self.len_encoded(format)];
        self.encode(format, &mut buffer);
        buffer.pop();
        buffer
    }

    #[inline]
    pub fn len_encoded(&self, format: Format) -> usize {
        unsafe { ffi::gcry_sexp_sprint(self.as_raw(), format as c_int, ptr::null_mut(), 0) }
    }

    #[inline]
    pub fn encode(&self, format: Format, buf: &mut [u8]) -> Option<usize> {
        unsafe {
            match ffi::gcry_sexp_sprint(
                self.as_raw(),
                format as c_int,
                buf.as_mut_ptr() as *mut _,
                buf.len(),
            ) {
                0 => None,
                x => Some(x),
            }
        }
    }

    #[inline]
    pub fn elements(&self) -> Elements {
        unsafe {
            Elements {
                sexp: self,
                first: 0,
                last: ffi::gcry_sexp_length(self.as_raw()),
            }
        }
    }

    #[inline]
    pub fn head(&self) -> Option<SExpression> {
        unsafe {
            ffi::gcry_sexp_car(self.as_raw())
                .as_mut()
                .map(|x| SExpression::from_raw(x))
        }
    }

    #[inline]
    pub fn tail(&self) -> Option<SExpression> {
        unsafe {
            ffi::gcry_sexp_cdr(self.as_raw())
                .as_mut()
                .map(|x| SExpression::from_raw(x))
        }
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    #[inline]
    pub fn len(&self) -> usize {
        unsafe { ffi::gcry_sexp_length(self.as_raw()) as usize }
    }

    #[inline]
    pub fn find_token<B: AsRef<[u8]>>(&self, token: B) -> Option<SExpression> {
        let token = token.as_ref();
        unsafe {
            ffi::gcry_sexp_find_token(self.as_raw(), token.as_ptr() as *const _, token.len())
                .as_mut()
                .map(|x| SExpression::from_raw(x))
        }
    }

    #[inline]
    pub fn get(&self, idx: u32) -> Option<SExpression> {
        unsafe {
            ffi::gcry_sexp_nth(self.as_raw(), idx as c_int)
                .as_mut()
                .map(|x| SExpression::from_raw(x))
        }
    }

    #[inline]
    pub fn get_bytes(&self, idx: u32) -> Option<&[u8]> {
        unsafe {
            let mut len = 0;
            ffi::gcry_sexp_nth_data(self.as_raw(), idx as c_int, &mut len)
                .as_ref()
                .map(|x| slice::from_raw_parts(x as *const _ as *const _, len))
        }
    }

    #[inline]
    pub fn get_str(&self, idx: u32) -> result::Result<&str, Option<Utf8Error>> {
        self.get_bytes(idx)
            .map_or(Err(None), |s| str::from_utf8(s).map_err(Some))
    }

    #[inline]
    pub fn get_integer(&self, idx: u32, fmt: IntegerFormat) -> Option<Integer> {
        unsafe {
            ffi::gcry_sexp_nth_mpi(self.as_raw(), idx as c_int, fmt as c_int)
                .as_mut()
                .map(|x| Integer::from_raw(x))
        }
    }
}

impl FromStr for SExpression {
    type Err = Error;

    #[inline]
    fn from_str(s: &str) -> Result<SExpression> {
        SExpression::from_bytes(s)
    }
}

impl fmt::Debug for SExpression {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::ascii;
        use std::fmt::Write;

        try!(write!(f, "SExpression(\""));
        for b in self.to_bytes(Format::Advanced)
            .into_iter()
            .flat_map(|b| ascii::escape_default(b))
        {
            try!(f.write_char(b as char));
        }
        write!(f, "\")")
    }
}

impl<'a> IntoIterator for &'a SExpression {
    type Item = SExpression;
    type IntoIter = Elements<'a>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.elements()
    }
}

#[derive(Debug)]
pub struct Elements<'a> {
    sexp: &'a SExpression,
    first: c_int,
    last: c_int,
}

impl<'a> Iterator for Elements<'a> {
    type Item = SExpression;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.first < self.last {
            let elem = unsafe {
                let raw = ffi::gcry_sexp_nth(self.sexp.as_raw(), self.first);
                SExpression::from_raw(raw)
            };
            self.first += 1;
            Some(elem)
        } else {
            None
        }
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<Self::Item> {
        self.first = if (n as u64) < (self.last as u64) {
            self.first + (n as c_int)
        } else {
            self.last
        };
        self.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let size = (self.last - self.first) as usize;
        (size, Some(size))
    }
}

impl<'a> DoubleEndedIterator for Elements<'a> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.first < self.last {
            self.last -= 1;
            unsafe {
                let raw = ffi::gcry_sexp_nth(self.sexp.as_raw(), self.last);
                Some(SExpression::from_raw(raw))
            }
        } else {
            None
        }
    }
}