<commit_before>//! Implement thread-local storage.

use std::collections::BTreeMap;

use rustc_target::abi::LayoutOf;
use rustc::{ty, ty::layout::HasDataLayout};

use crate::{
    InterpResult, StackPopCleanup,
    MPlaceTy, Scalar, Tag,
    HelpersEvalContextExt,
};

pub type TlsKey = u128;

#[derive(Copy, Clone, Debug)]
pub struct TlsEntry<'tcx> {
    /// The data for this key. None is used to represent NULL.
    /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.)
    /// Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread.
    pub(crate) data: Option<Scalar<Tag>>,
    pub(crate) dtor: Option<ty::Instance<'tcx>>,
}

#[derive(Debug)]
pub struct TlsData<'tcx> {
    /// The Key to use for the next thread-local allocation.
    pub(crate) next_key: TlsKey,

    /// pthreads-style thread-local storage.
    pub(crate) keys: BTreeMap<TlsKey, TlsEntry<'tcx>>,
}

impl<'tcx> Default for TlsData<'tcx> {
    fn default() -> Self {
        TlsData {
            next_key: 1, // start with 1 as we must not use 0 on Windows
            keys: Default::default(),
        }
    }
}

impl<'tcx> TlsData<'tcx> {
    pub fn create_tls_key(
        &mut self,
        dtor: Option<ty::Instance<'tcx>>,
    ) -> TlsKey {
        let new_key = self.next_key;
        self.next_key += 1;
        self.keys.insert(
            new_key,
            TlsEntry {
                data: None,
                dtor,
            },
        );
        trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor);
        new_key
    }

    pub fn delete_tls_key(&mut self, key: TlsKey) -> InterpResult<'tcx> {
        match self.keys.remove(&key) {
            Some(_) => {
                trace!("TLS key {} removed", key);
                Ok(())
            }
            None => throw_unsup!(TlsOutOfBounds),
        }
    }

    pub fn load_tls(
        &mut self,
        key: TlsKey,
        cx: &impl HasDataLayout,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        match self.keys.get(&key) {
            Some(&TlsEntry { data, .. }) => {
                trace!("TLS key {} loaded: {:?}", key, data);
                Ok(data.unwrap_or_else(|| Scalar::ptr_null(cx).into()))
            }
            None => throw_unsup!(TlsOutOfBounds),
        }
    }

    pub fn store_tls(&mut self, key: TlsKey, new_data: Option<Scalar<Tag>>) -> InterpResult<'tcx> {
        match self.keys.get_mut(&key) {
            Some(&mut TlsEntry { ref mut data, .. }) => {
                trace!("TLS key {} stored: {:?}", key, new_data);
                *data = new_data;
                Ok(())
            }
            None => throw_unsup!(TlsOutOfBounds),
        }
    }

    /// Returns a dtor, its argument and its index, if one is supposed to run
    ///
    /// An optional destructor function may be associated with each key value.
    /// At thread exit, if a key value has a non-NULL destructor pointer,
    /// and the thread has a non-NULL value associated with that key,
    /// the value of the key is set to NULL, and then the function pointed
    /// to is called with the previously associated value as its sole argument.
    /// The order of destructor calls is unspecified if more than one destructor
    /// exists for a thread when it exits.
    ///
    /// If, after all the destructors have been called for all non-NULL values
    /// with associated destructors, there are still some non-NULL values with
    /// associated destructors, then the process is repeated.
    /// If, after at least {PTHREAD_DESTRUCTOR_ITERATIONS} iterations of destructor
    /// calls for outstanding non-NULL values, there are still some non-NULL values
    /// with associated destructors, implementations may stop calling destructors,
    /// or they may continue calling destructors until no non-NULL values with
    /// associated destructors exist, even though this might result in an infinite loop.
    fn fetch_tls_dtor(
        &mut self,
        key: Option<TlsKey>,
    ) -> Option<(ty::Instance<'tcx>, Scalar<Tag>, TlsKey)> {
        use std::collections::Bound::*;

        let thread_local = &mut self.keys;
        let start = match key {
            Some(key) => Excluded(key),
            None => Unbounded,
        };
        for (&key, &mut TlsEntry { ref mut data, dtor }) in
            thread_local.range_mut((start, Unbounded))
        {
            if let Some(data_scalar) = *data {
                if let Some(dtor) = dtor {
                    let ret = Some((dtor, data_scalar, key));
                    *data = None;
                    return ret;
                }
            }
        }
        None
    }
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn run_tls_dtors(&mut self) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();
        let mut dtor = this.machine.tls.fetch_tls_dtor(None);
        // FIXME: replace loop by some structure that works with stepping
        while let Some((instance, ptr, key)) = dtor {
            trace!("Running TLS dtor {:?} on {:?}", instance, ptr);
            assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!");
            // TODO: Potentially, this has to support all the other possible instances?
            // See eval_fn_call in interpret/terminator/mod.rs
            let mir = this.load_mir(instance.def)?;
            let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
            this.push_stack_frame(
                instance,
                mir.span,
                mir,
                Some(ret_place),
                StackPopCleanup::None { cleanup: true },
            )?;
            let arg_local = this.frame().body.args_iter().next().ok_or_else(
                || err_ub_format!("TLS dtor does not take enough arguments."),
            )?;
            let dest = this.local_place(arg_local)?;
            this.write_scalar(ptr, dest)?;

            // step until out of stackframes
            this.run()?;

            dtor = match this.machine.tls.fetch_tls_dtor(Some(key)) {
                dtor @ Some(_) => dtor,
                None => this.machine.tls.fetch_tls_dtor(None),
            };
        }
        // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`.
        Ok(())
    }
}
<commit_msg>make TLS state private to TLS module<commit_after>//! Implement thread-local storage.

use std::collections::BTreeMap;

use rustc_target::abi::LayoutOf;
use rustc::{ty, ty::layout::HasDataLayout};

use crate::{
    InterpResult, StackPopCleanup,
    MPlaceTy, Scalar, Tag,
    HelpersEvalContextExt,
};

pub type TlsKey = u128;

#[derive(Copy, Clone, Debug)]
pub struct TlsEntry<'tcx> {
    /// The data for this key. None is used to represent NULL.
    /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.)
    /// Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread.
    data: Option<Scalar<Tag>>,
    dtor: Option<ty::Instance<'tcx>>,
}

#[derive(Debug)]
pub struct TlsData<'tcx> {
    /// The Key to use for the next thread-local allocation.
    next_key: TlsKey,

    /// pthreads-style thread-local storage.
    keys: BTreeMap<TlsKey, TlsEntry<'tcx>>,
}

impl<'tcx> Default for TlsData<'tcx> {
    fn default() -> Self {
        TlsData {
            next_key: 1, // start with 1 as we must not use 0 on Windows
            keys: Default::default(),
        }
    }
}

impl<'tcx> TlsData<'tcx> {
    pub fn create_tls_key(
        &mut self,
        dtor: Option<ty::Instance<'tcx>>,
    ) -> TlsKey {
        let new_key = self.next_key;
        self.next_key += 1;
        self.keys.insert(
            new_key,
            TlsEntry {
                data: None,
                dtor,
            },
        );
        trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor);
        new_key
    }

    pub fn delete_tls_key(&mut self, key: TlsKey) -> InterpResult<'tcx> {
        match self.keys.remove(&key) {
            Some(_) => {
                trace!("TLS key {} removed", key);
                Ok(())
            }
            None => throw_unsup!(TlsOutOfBounds),
        }
    }

    pub fn load_tls(
        &mut self,
        key: TlsKey,
        cx: &impl HasDataLayout,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        match self.keys.get(&key) {
            Some(&TlsEntry { data, .. }) => {
                trace!("TLS key {} loaded: {:?}", key, data);
                Ok(data.unwrap_or_else(|| Scalar::ptr_null(cx).into()))
            }
            None => throw_unsup!(TlsOutOfBounds),
        }
    }

    pub fn store_tls(&mut self, key: TlsKey, new_data: Option<Scalar<Tag>>) -> InterpResult<'tcx> {
        match self.keys.get_mut(&key) {
            Some(&mut TlsEntry { ref mut data, .. }) => {
                trace!("TLS key {} stored: {:?}", key, new_data);
                *data = new_data;
                Ok(())
            }
            None => throw_unsup!(TlsOutOfBounds),
        }
    }

    /// Returns a dtor, its argument and its index, if one is supposed to run
    ///
    /// An optional destructor function may be associated with each key value.
    /// At thread exit, if a key value has a non-NULL destructor pointer,
    /// and the thread has a non-NULL value associated with that key,
    /// the value of the key is set to NULL, and then the function pointed
    /// to is called with the previously associated value as its sole argument.
    /// The order of destructor calls is unspecified if more than one destructor
    /// exists for a thread when it exits.
    ///
    /// If, after all the destructors have been called for all non-NULL values
    /// with associated destructors, there are still some non-NULL values with
    /// associated destructors, then the process is repeated.
    /// If, after at least {PTHREAD_DESTRUCTOR_ITERATIONS} iterations of destructor
    /// calls for outstanding non-NULL values, there are still some non-NULL values
    /// with associated destructors, implementations may stop calling destructors,
    /// or they may continue calling destructors until no non-NULL values with
    /// associated destructors exist, even though this might result in an infinite loop.
    fn fetch_tls_dtor(
        &mut self,
        key: Option<TlsKey>,
    ) -> Option<(ty::Instance<'tcx>, Scalar<Tag>, TlsKey)> {
        use std::collections::Bound::*;

        let thread_local = &mut self.keys;
        let start = match key {
            Some(key) => Excluded(key),
            None => Unbounded,
        };
        for (&key, &mut TlsEntry { ref mut data, dtor }) in
            thread_local.range_mut((start, Unbounded))
        {
            if let Some(data_scalar) = *data {
                if let Some(dtor) = dtor {
                    let ret = Some((dtor, data_scalar, key));
                    *data = None;
                    return ret;
                }
            }
        }
        None
    }
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn run_tls_dtors(&mut self) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();
        let mut dtor = this.machine.tls.fetch_tls_dtor(None);
        // FIXME: replace loop by some structure that works with stepping
        while let Some((instance, ptr, key)) = dtor {
            trace!("Running TLS dtor {:?} on {:?}", instance, ptr);
            assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!");
            // TODO: Potentially, this has to support all the other possible instances?
            // See eval_fn_call in interpret/terminator/mod.rs
            let mir = this.load_mir(instance.def)?;
            let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
            this.push_stack_frame(
                instance,
                mir.span,
                mir,
                Some(ret_place),
                StackPopCleanup::None { cleanup: true },
            )?;
            let arg_local = this.frame().body.args_iter().next().ok_or_else(
                || err_ub_format!("TLS dtor does not take enough arguments."),
            )?;
            let dest = this.local_place(arg_local)?;
            this.write_scalar(ptr, dest)?;

            // step until out of stackframes
            this.run()?;

            dtor = match this.machine.tls.fetch_tls_dtor(Some(key)) {
                dtor @ Some(_) => dtor,
                None => this.machine.tls.fetch_tls_dtor(None),
            };
        }
        // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`.
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Shared mathematical utility functions.

use std::cmp::max;

/// Calculates the width and height an image should be resized to.
/// This preserves aspect ratio, and based on the `fill` parameter
/// will either fill the dimensions to fit inside the smaller constraint
/// (will overflow the specified bounds on one axis to preserve
/// aspect ratio), or will shrink so that both dimensions are
/// completely contained within the given `width` and `height`,
/// with empty space on one axis.
pub(crate) fn resize_dimensions(
    width: u32,
    height: u32,
    nwidth: u32,
    nheight: u32,
    fill: bool,
) -> (u32, u32) {
    let wratio = nwidth as f64 / width as f64;
    let hratio = nheight as f64 / height as f64;

    let ratio = if fill {
        f64::max(wratio, hratio)
    } else {
        f64::min(wratio, hratio)
    };

    let nw = max((width as f64 * ratio).round() as u64, 1);
    let nh = max((height as f64 * ratio).round() as u64, 1);

    if nw > u64::from(u32::MAX) {
        let ratio = u32::MAX as f64 / width as f64;
        (u32::MAX, max((height as f64 * ratio).round() as u32, 1))
    } else if nh > u64::from(u32::MAX) {
        let ratio = u32::MAX as f64 / height as f64;
        (max((width as f64 * ratio).round() as u32, 1), u32::MAX)
    } else {
        (nw as u32, nh as u32)
    }
}

#[cfg(test)]
mod test {
    quickcheck! {
        fn resize_bounds_correctly_width(old_w: u32, new_w: u32) -> bool {
            if old_w == 0 || new_w == 0 { return true; }
            if new_w as u64 * 400u64 >= old_w as u64 * u64::from(u32::MAX) { return true; }

            let result = super::resize_dimensions(old_w, 400, new_w, ::std::u32::MAX, false);
            let exact = (400 as f64 * new_w as f64 / old_w as f64).round() as u32;
            result.0 == new_w && result.1 == exact.max(1)
        }
    }

    quickcheck! {
        fn resize_bounds_correctly_height(old_h: u32, new_h: u32) -> bool {
            if old_h == 0 || new_h == 0 { return true; }
            if 400u64 * new_h as u64 >= old_h as u64 * u64::from(u32::MAX) { return true; }

            let result = super::resize_dimensions(400, old_h, ::std::u32::MAX, new_h, false);
            let exact = (400 as f64 * new_h as f64 / old_h as f64).round() as u32;
            result.1 == new_h && result.0 == exact.max(1)
        }
    }

    #[test]
    fn resize_handles_fill() {
        let result = super::resize_dimensions(100, 200, 200, 500, true);
        assert!(result.0 == 250);
        assert!(result.1 == 500);

        let result = super::resize_dimensions(200, 100, 500, 200, true);
        assert!(result.0 == 500);
        assert!(result.1 == 250);
    }

    #[test]
    fn resize_never_rounds_to_zero() {
        let result = super::resize_dimensions(1, 150, 128, 128, false);
        assert!(result.0 > 0);
        assert!(result.1 > 0);
    }

    #[test]
    fn resize_handles_overflow() {
        let result = super::resize_dimensions(100, ::std::u32::MAX, 200, ::std::u32::MAX, true);
        assert!(result.0 == 100);
        assert!(result.1 == ::std::u32::MAX);

        let result = super::resize_dimensions(::std::u32::MAX, 100, ::std::u32::MAX, 200, true);
        assert!(result.0 == ::std::u32::MAX);
        assert!(result.1 == 100);
    }

    #[test]
    fn resize_rounds() {
        // Only truncation will result in (3840, 2229) and (2160, 3719)
        let result = super::resize_dimensions(4264, 2476, 3840, 2160, true);
        assert_eq!(result, (3840, 2230));

        let result = super::resize_dimensions(2476, 4264, 2160, 3840, false);
        assert_eq!(result, (2160, 3720));
    }

    #[test]
    fn resize_handles_zero() {
        let result = super::resize_dimensions(0, 100, 100, 100, false);
        assert_eq!(result, (1, 100));

        let result = super::resize_dimensions(100, 0, 100, 100, false);
        assert_eq!(result, (100, 1));

        let result = super::resize_dimensions(100, 100, 0, 100, false);
        assert_eq!(result, (1, 1));

        let result = super::resize_dimensions(100, 100, 100, 0, false);
        assert_eq!(result, (1, 1));
    }
}
<commit_msg>Comment exception in utils quickcheck<commit_after>//! Shared mathematical utility functions.

use std::cmp::max;

/// Calculates the width and height an image should be resized to.
/// This preserves aspect ratio, and based on the `fill` parameter
/// will either fill the dimensions to fit inside the smaller constraint
/// (will overflow the specified bounds on one axis to preserve
/// aspect ratio), or will shrink so that both dimensions are
/// completely contained within the given `width` and `height`,
/// with empty space on one axis.
pub(crate) fn resize_dimensions(
    width: u32,
    height: u32,
    nwidth: u32,
    nheight: u32,
    fill: bool,
) -> (u32, u32) {
    let wratio = nwidth as f64 / width as f64;
    let hratio = nheight as f64 / height as f64;

    let ratio = if fill {
        f64::max(wratio, hratio)
    } else {
        f64::min(wratio, hratio)
    };

    let nw = max((width as f64 * ratio).round() as u64, 1);
    let nh = max((height as f64 * ratio).round() as u64, 1);

    if nw > u64::from(u32::MAX) {
        let ratio = u32::MAX as f64 / width as f64;
        (u32::MAX, max((height as f64 * ratio).round() as u32, 1))
    } else if nh > u64::from(u32::MAX) {
        let ratio = u32::MAX as f64 / height as f64;
        (max((width as f64 * ratio).round() as u32, 1), u32::MAX)
    } else {
        (nw as u32, nh as u32)
    }
}

#[cfg(test)]
mod test {
    quickcheck! {
        fn resize_bounds_correctly_width(old_w: u32, new_w: u32) -> bool {
            if old_w == 0 || new_w == 0 { return true; }
            // In this case, the scaling is limited by scaling of height.
            // We could check that case separately but it does not conform to the same expectation.
            if new_w as u64 * 400u64 >= old_w as u64 * u64::from(u32::MAX) { return true; }

            let result = super::resize_dimensions(old_w, 400, new_w, ::std::u32::MAX, false);
            let exact = (400 as f64 * new_w as f64 / old_w as f64).round() as u32;
            result.0 == new_w && result.1 == exact.max(1)
        }
    }

    quickcheck! {
        fn resize_bounds_correctly_height(old_h: u32, new_h: u32) -> bool {
            if old_h == 0 || new_h == 0 { return true; }
            // In this case, the scaling is limited by scaling of width.
            // We could check that case separately but it does not conform to the same expectation.
            if 400u64 * new_h as u64 >= old_h as u64 * u64::from(u32::MAX) { return true; }

            let result = super::resize_dimensions(400, old_h, ::std::u32::MAX, new_h, false);
            let exact = (400 as f64 * new_h as f64 / old_h as f64).round() as u32;
            result.1 == new_h && result.0 == exact.max(1)
        }
    }

    #[test]
    fn resize_handles_fill() {
        let result = super::resize_dimensions(100, 200, 200, 500, true);
        assert!(result.0 == 250);
        assert!(result.1 == 500);

        let result = super::resize_dimensions(200, 100, 500, 200, true);
        assert!(result.0 == 500);
        assert!(result.1 == 250);
    }

    #[test]
    fn resize_never_rounds_to_zero() {
        let result = super::resize_dimensions(1, 150, 128, 128, false);
        assert!(result.0 > 0);
        assert!(result.1 > 0);
    }

    #[test]
    fn resize_handles_overflow() {
        let result = super::resize_dimensions(100, ::std::u32::MAX, 200, ::std::u32::MAX, true);
        assert!(result.0 == 100);
        assert!(result.1 == ::std::u32::MAX);

        let result = super::resize_dimensions(::std::u32::MAX, 100, ::std::u32::MAX, 200, true);
        assert!(result.0 == ::std::u32::MAX);
        assert!(result.1 == 100);
    }

    #[test]
    fn resize_rounds() {
        // Only truncation will result in (3840, 2229) and (2160, 3719)
        let result = super::resize_dimensions(4264, 2476, 3840, 2160, true);
        assert_eq!(result, (3840, 2230));

        let result = super::resize_dimensions(2476, 4264, 2160, 3840, false);
        assert_eq!(result, (2160, 3720));
    }

    #[test]
    fn resize_handles_zero() {
        let result = super::resize_dimensions(0, 100, 100, 100, false);
        assert_eq!(result, (1, 100));

        let result = super::resize_dimensions(100, 0, 100, 100, false);
        assert_eq!(result, (100, 1));

        let result = super::resize_dimensions(100, 100, 0, 100, false);
        assert_eq!(result, (1, 1));

        let result = super::resize_dimensions(100, 100, 100, 0, false);
        assert_eq!(result, (1, 1));
    }
}
<|endoftext|>


<commit_before>use std::io;
use lamport_sigs::{PrivateKey, PublicKey, LamportSignatureData};
use crypto::digest::Digest;
use merkle::{MerkleTree, Proof};
use std::io::{Error, ErrorKind};

pub type MerkleSignature<D> = (LamportSignatureData, Proof<D, PublicKey<D>>);
pub type MerkleSignedData<D, T> = (Vec<T>, MerkleSignature<D>);

// TODO: Error management. Currently forcing unwrap within the map.
// We can leave optionals to avoid having panics.
pub fn sign_data_vec<D: Digest + Clone, T: AsRef<[u8]>>(data: &Vec<T>,
                                                        digest: D)
                                                        -> io::Result<Vec<MerkleSignature<D>>> {
    let mut leaf_keys: Vec<PrivateKey<D>> = vec![PrivateKey::new(digest.clone()); data.len()];
    let leaf_pub_keys = leaf_keys.iter()
        .map(|priv_key| priv_key.public_key())
        .collect::<Vec<_>>();

    let tree_opt =  MerkleTree::from_vec(digest, leaf_pub_keys.clone());

    if tree_opt.is_none() {
        return Err(Error::new(ErrorKind::Other,
        "A signature could not be produced because an issue occured generating the signing tree."));
    }

    let tree = tree_opt.unwrap();

    let proofs = leaf_pub_keys.into_iter()
        .map(|pub_key| (tree.gen_proof(pub_key).unwrap()))
        .collect::<Vec<_>>();

    let signatures = leaf_keys.iter_mut()
        .zip(data.iter())
        .map(|(mut priv_key, data)| priv_key.sign(data.as_ref()).unwrap())
        .collect::<Vec<_>>();

    Ok(signatures.into_iter()
              .zip(proofs)
              .map(|(sigs, proof)| (sigs, proof))
              .collect::<Vec<_>>())
}

/// Verifies the signature of the data. Returns an error if data couldn't be verified.
pub fn verify_data_vec_signature<D: Digest+Clone, T: Into<Vec<u8>>>(data: T,
    signature: &MerkleSignature<D>, root_hash: &Vec<u8>) -> io::Result<()>{
    let (ref sig, ref proof) = *signature;

    let valid_root = proof.validate(root_hash);
    let data_vec: Vec<u8> = data.into();
    let valid_sig = proof.value.verify_signature(sig, data_vec.as_slice());

    if !valid_root {
        return Err(Error::new(ErrorKind::Other, "The inclusion proof failed to validate."));
    }

    if !valid_sig {
        return Err(Error::new(ErrorKind::Other,
                              "The signature could not be properly verified."));
    }

    Ok(())
}
<commit_msg>Improve error-handling.<commit_after>use std::io;
use lamport_sigs::{PrivateKey, PublicKey, LamportSignatureData};
use crypto::digest::Digest;
use merkle::{MerkleTree, Proof};
use std::io::{Error, ErrorKind};

pub type MerkleSignature<D> = (LamportSignatureData, Proof<D, PublicKey<D>>);
pub type MerkleSignedData<D, T> = (Vec<T>, MerkleSignature<D>);

fn new_err(reason: &str) -> Error {
    Error::new(ErrorKind::Other, format!("A signature could not be produced because {}", reason))
}

pub fn sign_data_vec<D, T>(data: &Vec<T>, digest: D) -> io::Result<Vec<MerkleSignature<D>>>
        where D: Digest + Clone, T: AsRef<[u8]> {

    let mut leaf_keys = vec![PrivateKey::new(digest.clone()); data.len()];
    let leaf_pub_keys = leaf_keys.iter()
        .map(|priv_key| priv_key.public_key())
        .collect::<Vec<_>>();

    let tree_opt = MerkleTree::from_vec(digest, leaf_pub_keys.clone());

    if tree_opt.is_none() {
        return Err(new_err("an issue occured while generating the signing tree."));
    }

    let tree = tree_opt.unwrap();

    let proofs_opt = leaf_pub_keys.into_iter()
        .map(|pub_key| tree.gen_proof(pub_key))
        .collect::<Option<Vec<_>>>();

    let signatures_opt = leaf_keys.iter_mut()
        .zip(data.iter())
        .map(|(mut priv_key, data)| priv_key.sign(data.as_ref()))
        .collect::<Result<Vec<_>, _>>();

    match (signatures_opt, proofs_opt) {
        (_, None) =>
            Err(new_err("an issue occured while generating the inclusion proofs.")),

        (Err(err), _) =>
            Err(new_err(&format!("an issue occured while signing the data: {}", err))),

        (Ok(signatures), Some(proofs)) =>
            Ok(signatures.into_iter().zip(proofs).collect())
    }
}

/// Verifies the signature of the data. Returns an error if data couldn't be verified.
pub fn verify_data_vec_signature<D, T>(data: T, signature: &MerkleSignature<D>, root_hash: &Vec<u8>) -> io::Result<()>
        where D: Digest + Clone, T: Into<Vec<u8>> {

    let (ref sig, ref proof) = *signature;

    let valid_root = proof.validate(root_hash);
    let data_vec   = data.into() as Vec<u8>;
    let valid_sig  = proof.value.verify_signature(sig, data_vec.as_slice());

    if !valid_root {
        return Err(Error::new(ErrorKind::Other,
                              "The inclusion proof failed to validate."));
    }

    if !valid_sig {
        return Err(Error::new(ErrorKind::Other,
                              "The signature could not be properly verified."));
    }

    Ok(())
}
<|endoftext|>


<commit_before>extern crate cc3200_sys;

use core::convert::TryFrom;
use core::mem;
use core::ptr;
use core::slice;
use core::str;

pub use self::cc3200_sys::simplelink::*;

macro_rules! try_wlan {
    ($e:expr) => ({
        let rc: i16 = unsafe { $e };
        if rc < 0 {
            return Err(SimpleLinkError::Wlan(try!(WlanError::try_from(rc))));
        }
        rc
    })
}

pub struct SimpleLink { }

impl SimpleLink {
    pub fn start_spawn_task() -> Result<(), SimpleLinkError> {
        let rc = unsafe { VStartSimpleLinkSpawnTask(SPAWN_TASK_PRIORITY) };
        if rc < 0 {
            Err(SimpleLinkError::Osi(try!(OsiError::try_from(rc))))
        } else {
            Ok(())
        }
    }

    pub fn get_version() -> SlVersionFull {
        let mut version: SlVersionFull = Default::default();
        unsafe { simplelink_get_version(&mut version) };
        version
    }

    pub fn get_driver_version() -> &'static str {
        let mut ver_len: u32 = 0;
        unsafe {
            let ver_ptr = simplelink_get_driver_version(&mut ver_len);
            str::from_utf8_unchecked(slice::from_raw_parts(ver_ptr, ver_len as usize))
        }
    }

    // App Variables

    pub fn init_app_variables() {
        unsafe {
            simplelink_init_app_variables();
        }
    }

    pub fn is_ip_acquired() -> bool {
        unsafe { simplelink_get_status_bit(StatusBit::STATUS_BIT_IP_AQUIRED as u32) }
    }

    pub fn is_connected() -> bool {
        unsafe { simplelink_get_status_bit(StatusBit::STATUS_BIT_CONNECTION as u32) }
    }

    pub fn is_ping_done() -> bool {
        unsafe { simplelink_get_status_bit(StatusBit::STATUS_BIT_PING_DONE as u32) }
    }

    pub fn clear_ping_done() {
        unsafe { simplelink_clear_status_bit(StatusBit::STATUS_BIT_PING_DONE as u32) };
    }

    pub fn gateway_ip() -> u32 {
        unsafe { simplelink_gateway_ip() }
    }

    pub fn ping_packets_received() -> u32 {
        unsafe { simplelink_ping_packets_received() }
    }

    // Device

    pub fn start() -> Result<WlanMode, SimpleLinkError> {
        let rc = try_wlan!(sl_Start(ptr::null(), ptr::null(), None));
        Ok(try!(WlanMode::try_from(rc)))
    }

    pub fn stop(timeout_msecs: u16) -> Result<WlanMode, SimpleLinkError> {
        let rc = try_wlan!(sl_Stop(timeout_msecs));
        Ok(try!(WlanMode::try_from(rc)))
    }

    // Net App

    pub fn netapp_get_host_by_name(name: &str) -> Result<u32, SimpleLinkError> {
        let mut out_ip_addr: u32 = 0;
        try_wlan!(sl_NetAppDnsGetHostByName(name.as_ptr(), name.len() as u16, &mut out_ip_addr as *mut u32, SocketFamily::AF_INET as u8));
        Ok(out_ip_addr)
    }

    pub fn netapp_mdns_unregister_service(name: &str) -> Result<(), SimpleLinkError> {
        let name_len = name.len() as u8;
        let name_ptr = { if name_len > 0 { name.as_ptr() } else { ptr::null() }};
        try_wlan!(sl_NetAppMDNSUnRegisterService(name_ptr, name_len));
        Ok(())
    }

    pub fn netapp_ping_start(ping_params: &SlPingStartCommand,
                            family: SocketFamily) -> Result<(), SimpleLinkError> {
        let params_ptr = ping_params as *const SlPingStartCommand;

        // Since we're provinding a callback, the ping_report parameter is ignored.
        try_wlan!(sl_NetAppPingStart(params_ptr, family as u8, ptr::null_mut(), Some(SimpleLinkPingReport)));
        Ok(())
    }

    // Net Config

    pub fn netcfg_set(config: NetConfigSet, val: &[u8]) -> Result<(), SimpleLinkError> {
        let config_id = ((config as u32 & 0xff00) >> 8) as u8;
        let config_opt = (config as u32 & 0x00ff) as u8;
        try_wlan!(sl_NetCfgSet(config_id, config_opt, val.len() as u8, val.as_ptr()) as i16);
        Ok(())
    }

    // WLAN

    pub fn wlan_delete_profile(index: i16) -> Result<(), SimpleLinkError> {
        try_wlan!(sl_WlanProfileDel(index));
        Ok(())
    }

    pub fn wlan_connect(ssid: &str, mac_addr: &[u8], sec_params: Option<SlSecParams>, sec_params_ext: Option<SlSecParamsExt>) -> Result<(), SimpleLinkError> {
        let ssid_ptr = ssid.as_ptr();
        let ssid_len = ssid.len() as i16;
        let mac_addr_len = mac_addr.len();
        let mac_addr_ptr = if mac_addr_len > 0 { mac_addr.as_ptr() } else { ptr::null() as *const u8 };
        let sec_params_ptr: *const SlSecParams = sec_params.map(|r| &r as *const SlSecParams).unwrap_or(ptr::null() as *const SlSecParams);
        let sec_params_ext_ptr: *const SlSecParamsExt = sec_params_ext.map(|r| &r as *const SlSecParamsExt).unwrap_or(ptr::null() as *const SlSecParamsExt);
        try_wlan!(sl_WlanConnect(ssid_ptr, ssid_len, mac_addr_ptr, sec_params_ptr, sec_params_ext_ptr));
        Ok(())
    }

    pub fn wlan_disconnect() -> Result<(), SimpleLinkError> {
        try_wlan!(sl_WlanDisconnect());
        Ok(())
    }
    pub fn wlan_set(config: WlanConfig, val: &[u8]) -> Result<(), SimpleLinkError> {
        let config_id = ((config as u32 & 0xff00) >> 8) as u16;
        let config_opt = (config as u32 & 0x00ff) as u16;
        try_wlan!(sl_WlanSet(config_id, config_opt, val.len() as u16, val.as_ptr()));
        Ok(())
    }

    pub fn wlan_set_mode(mode: WlanMode) -> Result<WlanMode, SimpleLinkError> {
        let rc = try_wlan!(sl_WlanSetMode(mode as u8));
        Ok(try!(WlanMode::try_from(rc)))
    }

    pub fn wlan_set_policy(policy: Policy, val: &[u8]) -> Result<(), SimpleLinkError> {
        let policy_type = ((policy as u32 & 0xff00) >> 8) as u8;
        let policy_policy = (policy as u32 & 0x00ff) as u8;
        try_wlan!(sl_WlanPolicySet(policy_type, policy_policy, val.as_ptr(), val.len() as u8));
        Ok(())
    }

    // WLAN Rx Filter

    pub fn wlan_rx_filter(op: WlanRxFilterOp, buf: &WlanRxFilterOpBuf) -> Result<(), SimpleLinkError> {
        let buf_size = mem::size_of::<WlanRxFilterOpBuf>() as u16;
        let buf_ptr: *const u8 = buf as *const _ as *const u8;
        try_wlan!(sl_WlanRxFilterSet(op as u8, buf_ptr, buf_size));
        Ok(())
    }
}
<commit_msg>Fix call to wlan_connect (#43)<commit_after>extern crate cc3200_sys;

use core::convert::TryFrom;
use core::mem;
use core::ptr;
use core::slice;
use core::str;

pub use self::cc3200_sys::simplelink::*;

macro_rules! try_wlan {
    ($e:expr) => ({
        let rc: i16 = unsafe { $e };
        if rc < 0 {
            return Err(SimpleLinkError::Wlan(try!(WlanError::try_from(rc))));
        }
        rc
    })
}

pub struct SimpleLink { }

impl SimpleLink {
    pub fn start_spawn_task() -> Result<(), SimpleLinkError> {
        let rc = unsafe { VStartSimpleLinkSpawnTask(SPAWN_TASK_PRIORITY) };
        if rc < 0 {
            Err(SimpleLinkError::Osi(try!(OsiError::try_from(rc))))
        } else {
            Ok(())
        }
    }

    pub fn get_version() -> SlVersionFull {
        let mut version: SlVersionFull = Default::default();
        unsafe { simplelink_get_version(&mut version) };
        version
    }

    pub fn get_driver_version() -> &'static str {
        let mut ver_len: u32 = 0;
        unsafe {
            let ver_ptr = simplelink_get_driver_version(&mut ver_len);
            str::from_utf8_unchecked(slice::from_raw_parts(ver_ptr, ver_len as usize))
        }
    }

    // App Variables

    pub fn init_app_variables() {
        unsafe {
            simplelink_init_app_variables();
        }
    }

    pub fn is_ip_acquired() -> bool {
        unsafe { simplelink_get_status_bit(StatusBit::STATUS_BIT_IP_AQUIRED as u32) }
    }

    pub fn is_connected() -> bool {
        unsafe { simplelink_get_status_bit(StatusBit::STATUS_BIT_CONNECTION as u32) }
    }

    pub fn is_ping_done() -> bool {
        unsafe { simplelink_get_status_bit(StatusBit::STATUS_BIT_PING_DONE as u32) }
    }

    pub fn clear_ping_done() {
        unsafe { simplelink_clear_status_bit(StatusBit::STATUS_BIT_PING_DONE as u32) };
    }

    pub fn gateway_ip() -> u32 {
        unsafe { simplelink_gateway_ip() }
    }

    pub fn ping_packets_received() -> u32 {
        unsafe { simplelink_ping_packets_received() }
    }

    // Device

    pub fn start() -> Result<WlanMode, SimpleLinkError> {
        let rc = try_wlan!(sl_Start(ptr::null(), ptr::null(), None));
        Ok(try!(WlanMode::try_from(rc)))
    }

    pub fn stop(timeout_msecs: u16) -> Result<WlanMode, SimpleLinkError> {
        let rc = try_wlan!(sl_Stop(timeout_msecs));
        Ok(try!(WlanMode::try_from(rc)))
    }

    // Net App

    pub fn netapp_get_host_by_name(name: &str) -> Result<u32, SimpleLinkError> {
        let mut out_ip_addr: u32 = 0;
        try_wlan!(sl_NetAppDnsGetHostByName(name.as_ptr(), name.len() as u16, &mut out_ip_addr as *mut u32, SocketFamily::AF_INET as u8));
        Ok(out_ip_addr)
    }

    pub fn netapp_mdns_unregister_service(name: &str) -> Result<(), SimpleLinkError> {
        let name_len = name.len() as u8;
        let name_ptr = { if name_len > 0 { name.as_ptr() } else { ptr::null() }};
        try_wlan!(sl_NetAppMDNSUnRegisterService(name_ptr, name_len));
        Ok(())
    }

    pub fn netapp_ping_start(ping_params: &SlPingStartCommand,
                            family: SocketFamily) -> Result<(), SimpleLinkError> {
        let params_ptr = ping_params as *const SlPingStartCommand;

        // Since we're provinding a callback, the ping_report parameter is ignored.
        try_wlan!(sl_NetAppPingStart(params_ptr, family as u8, ptr::null_mut(), Some(SimpleLinkPingReport)));
        Ok(())
    }

    // Net Config

    pub fn netcfg_set(config: NetConfigSet, val: &[u8]) -> Result<(), SimpleLinkError> {
        let config_id = ((config as u32 & 0xff00) >> 8) as u8;
        let config_opt = (config as u32 & 0x00ff) as u8;
        try_wlan!(sl_NetCfgSet(config_id, config_opt, val.len() as u8, val.as_ptr()) as i16);
        Ok(())
    }

    // WLAN

    pub fn wlan_delete_profile(index: i16) -> Result<(), SimpleLinkError> {
        try_wlan!(sl_WlanProfileDel(index));
        Ok(())
    }

    pub fn wlan_connect(ssid: &str, mac_addr: &[u8], sec_params: Option<SlSecParams>, sec_params_ext: Option<SlSecParamsExt>) -> Result<(), SimpleLinkError> {
        let ssid_ptr = ssid.as_ptr();
        let ssid_len = ssid.len() as i16;
        let mac_addr_len = mac_addr.len();
        let mac_addr_ptr = if mac_addr_len > 0 { mac_addr.as_ptr() } else { ptr::null() };
        let sec_params_ptr = sec_params.as_ref().map(|r| r as *const SlSecParams).unwrap_or(ptr::null());
        let sec_params_ext_ptr = sec_params_ext.as_ref().map(|r| r as *const SlSecParamsExt).unwrap_or(ptr::null());
        try_wlan!(sl_WlanConnect(ssid_ptr, ssid_len, mac_addr_ptr, sec_params_ptr, sec_params_ext_ptr));
        Ok(())
    }

    pub fn wlan_disconnect() -> Result<(), SimpleLinkError> {
        try_wlan!(sl_WlanDisconnect());
        Ok(())
    }
    pub fn wlan_set(config: WlanConfig, val: &[u8]) -> Result<(), SimpleLinkError> {
        let config_id = ((config as u32 & 0xff00) >> 8) as u16;
        let config_opt = (config as u32 & 0x00ff) as u16;
        try_wlan!(sl_WlanSet(config_id, config_opt, val.len() as u16, val.as_ptr()));
        Ok(())
    }

    pub fn wlan_set_mode(mode: WlanMode) -> Result<WlanMode, SimpleLinkError> {
        let rc = try_wlan!(sl_WlanSetMode(mode as u8));
        Ok(try!(WlanMode::try_from(rc)))
    }

    pub fn wlan_set_policy(policy: Policy, val: &[u8]) -> Result<(), SimpleLinkError> {
        let policy_type = ((policy as u32 & 0xff00) >> 8) as u8;
        let policy_policy = (policy as u32 & 0x00ff) as u8;
        try_wlan!(sl_WlanPolicySet(policy_type, policy_policy, val.as_ptr(), val.len() as u8));
        Ok(())
    }

    // WLAN Rx Filter

    pub fn wlan_rx_filter(op: WlanRxFilterOp, buf: &WlanRxFilterOpBuf) -> Result<(), SimpleLinkError> {
        let buf_size = mem::size_of::<WlanRxFilterOpBuf>() as u16;
        let buf_ptr: *const u8 = buf as *const _ as *const u8;
        try_wlan!(sl_WlanRxFilterSet(op as u8, buf_ptr, buf_size));
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Middle layer providing a somewhat safer (but still quite unsafe) API.
//!
//! The main idea is to wrap types `ffi_cif` and `ffi_closure` as `Cif` and
//! `Closure`, respectively, so that the resources are managed properly.
//! Calling a function via a CIF or closure is still unsafe.
use std::os::raw::c_void;
use std::marker::PhantomData;

use low;
pub use low::{Callback, CallbackMut, CodePtr,
              ffi_abi as FfiAbi, FFI_DEFAULT_ABI};

pub mod types;
use self::types::*;

/// When calling a function via a CIF, each argument must be passed
/// as a C `void*`. Wrapping the argument in the `Arg` struct
/// accomplishes the necessary coercion.
#[derive(Debug)]
#[repr(C)]
pub struct Arg(*mut c_void);

impl Arg {
    /// Coerces an argument reference into the `Arg` types.
    pub fn new<T>(r: &T) -> Self {
        Arg(r as *const T as *mut c_void)
    }
}

/// Coerces an argument reference into the `Arg` types. (This is the same
/// as [`Arg::new`](struct.Arg.html#method.new)).
pub fn arg<T>(r: &T) -> Arg {
    Arg::new(r)
}

/// A CIF (“Call InterFace”) describing the calling convention and types
/// for calling a function.
#[derive(Clone, Debug)]
pub struct Cif {
    cif:    low::ffi_cif,
    args:   TypeArray,
    result: Type,
}

impl Cif {
    /// Creates a new CIF for the given argument and result types,
    /// using the default calling convention.
    pub fn new<I>(args: I, result: Type) -> Self
        where I: ExactSizeIterator<Item=Type>
    {
        Self::from_type_array(TypeArray::new(args), result)
    }

    /// Sets the CIF to use the given calling convention.
    pub fn set_abi(&mut self, abi: FfiAbi) {
        self.cif.abi = abi;
    }

    /// Creates a new CIF for the given argument and result types,
    /// using the default calling convention.
    pub fn from_type_array(args: TypeArray, result: Type) -> Self {
        let mut cif: low::ffi_cif = Default::default();

        unsafe {
            low::prep_cif(&mut cif,
                          low::FFI_DEFAULT_ABI,
                          args.len(),
                          result.as_raw_ptr(),
                          args.as_raw_ptr())
        }.expect("low::prep_cif");

        // Note that cif retains references to args and result,
        // which is why we hold onto them here.
        Cif {
            cif:    cif,
            args:   args,
            result: result,
        }
    }

    /// Calls function `f` passing it the given arguments. Note that
    /// the funtion pointer is passed as a `usize`, which tends to be
    /// more convenient (and the types aren’t checked anyway).
    pub unsafe fn call<R>(&self, f: CodePtr, values: &[Arg]) -> R {
        use std::mem;

        assert!(self.cif.nargs as usize == values.len(),
                "Cif::call: passed wrong number of arguments");

        low::call::<R>(&self.cif as *const _ as *mut _,
                       f,
                       mem::transmute::<*const Arg,
                                        *mut *mut c_void>(values.as_ptr()))
    }

    /// Gets a raw pointer to the underlying
    /// [`ffi_cif`](../low/struct.ffi_cif.html). This can be used
    /// for passing the CIF to functions from the [`low`](../low/index.html)
    /// and [`raw`](../raw/index.html) modules.
    pub fn as_raw_ptr(&self) -> *mut low::ffi_cif {
        &self.cif as *const _ as *mut _
    }
}

/// Represents a closure, which captures a `void*` (user data) and
/// passes it to a callback when the code pointer (obtained via
/// [`code_ptr`](struct.Closure.html#method.code_ptr) is invoked.
pub struct Closure<'a> {
    _cif:    Box<Cif>,
    alloc:   *mut ::low::ffi_closure,
    code:    CodePtr,
    _marker: PhantomData<&'a ()>,
}

impl<'a> Drop for Closure<'a> {
    fn drop(&mut self) {
        unsafe {
            low::closure_free(self.alloc);
        }
    }
}

impl<'a> Closure<'a> {
    /// Creates a new closure. The CIF describes the calling convention
    /// for the resulting C function. When called, the C function will
    /// call `callback`, passing along its arguments and the captured
    /// `userdata`.
    pub fn new<U, R>(cif:      Cif,
                     callback: Callback<U, R>,
                     userdata: &'a U) -> Self
    {
        let cif = Box::new(cif);
        let (alloc, code) = low::closure_alloc();

        unsafe {
            low::prep_closure(alloc,
                              cif.as_raw_ptr(),
                              callback,
                              userdata as *const U,
                              code).unwrap();
        }

        Closure {
            _cif:    cif,
            alloc:   alloc,
            code:    code,
            _marker: PhantomData,
        }
    }

    /// Creates a new mutable closure. The CIF describes the calling convention
    /// for the resulting C function. When called, the C function will
    /// call `callback`, passing along its arguments and the captured
    /// `userdata`.
    pub fn new_mut<U, R>(cif:      Cif,
                         callback: CallbackMut<U, R>,
                         userdata: &'a mut U) -> Self
    {
        let cif = Box::new(cif);
        let (alloc, code) = low::closure_alloc();

        unsafe {
            low::prep_closure_mut(alloc,
                                  cif.as_raw_ptr(),
                                  callback,
                                  userdata as *mut U,
                                  code).unwrap();
        }

        Closure {
            _cif:    cif,
            alloc:   alloc,
            code:    code,
            _marker: PhantomData,
        }
    }

    /// Obtains the callable code pointer for a closure. The result
    /// needs to be transmuted to the correct type before it can be called.
    pub fn code_ptr(&self) -> &unsafe extern "C" fn() {
        self.code.as_fun()
    }
}

#[cfg(test)]
mod test {
    use low;
    use super::*;
    use super::types::*;
    use std::mem;
    use std::os::raw::c_void;

    #[test]
    fn call() {
        let cif  = Cif::new(vec![Type::i64(), Type::i64()].into_iter(),
                            Type::i64());
        let f    = |m: i64, n: i64| -> i64 {
            unsafe { cif.call(CodePtr(add_it as *mut c_void),
                              &[arg(&m), arg(&n)]) }
        };

        assert_eq!(12, f(5, 7));
        assert_eq!(13, f(6, 7));
        assert_eq!(15, f(8, 7));
    }

    extern "C" fn add_it(n: i64, m: i64) -> i64 {
        return n + m;
    }

    #[test]
    fn closure() {
        let cif  = Cif::new(vec![Type::u64()].into_iter(), Type::u64());
        let env: u64 = 5;
        let closure = Closure::new(cif, callback, &env);

        unsafe {
            let fun: &unsafe extern "C" fn(u64) -> u64
                = mem::transmute(closure.code_ptr());

            assert_eq!(11, fun(6));
            assert_eq!(12, fun(7));
        }
    }

    unsafe extern "C" fn callback(_cif: &low::ffi_cif,
                                  result: &mut u64,
                                  args: *const *const c_void,
                                  userdata: &u64)
    {
        let args: *const &u64 = mem::transmute(args);
        *result = **args + *userdata;
    }

    #[test]
    fn rust_lambda() {
        let cif = Cif::new(vec![Type::u64(), Type::u64()].into_iter(),
                           Type::u64());
        let env = |x: u64, y: u64| x + y;
        let closure = Closure::new(cif, callback2, &env);

        unsafe {
            let fun: &unsafe extern "C" fn (u64, u64) -> u64
                = mem::transmute(closure.code_ptr());

            assert_eq!(11, fun(5, 6));
        }
    }

    unsafe extern "C" fn callback2<F: Fn(u64, u64) -> u64>
        (_cif: &low::ffi_cif,
         result: &mut u64,
         args: *const *const c_void,
         userdata: &F)
    {
        let args: *const &u64 = mem::transmute(args);
        let arg1 = **args.offset(0);
        let arg2 = **args.offset(1);

        *result = userdata(arg1, arg2);
    }
}
<commit_msg>documented middle::Cif<commit_after>//! Middle layer providing a somewhat safer (but still quite unsafe)
//! API.
//!
//! The main idea of the middle layer is to wrap types
//! [`ffi_cif`](../raw/struct.ffi_cif.html) and
//! [`ffi_closure`](../raw/struct.ffi_closure.html) as
//! [`Cif`](struct.Cif.html) and [`Closure`](struct.Closure.html),
//! respectively, so that their resources are managed properly. However,
//! calling a function via a CIF or closure is still unsafe because
//! argument types aren’t checked. See the [`high`](../high/index.html)
//! layer for closures with type-checked arguments.
//!
use std::os::raw::c_void; use std::marker::PhantomData;

use low;
pub use low::{Callback, CallbackMut, CodePtr,
              ffi_abi as FfiAbi, FFI_DEFAULT_ABI};

pub mod types;
pub use self::types::Type;

/// Contains an untyped pointer to a function argument.
///
/// When calling a function via a [CIF](struct.Cif.html), each argument
/// must be passed as a C `void*`. Wrapping the argument in the `Arg`
/// struct accomplishes the necessary coercion.
#[derive(Debug)]
#[repr(C)]
pub struct Arg(*mut c_void);

impl Arg {
    /// Coerces an argument reference into the `Arg` type.
    ///
    /// This is used to wrap each argument pointer before passing them
    /// to [`Cif::call`](struct.Cif.html#method.call).
    pub fn new<T>(r: &T) -> Self {
        Arg(r as *const T as *mut c_void)
    }
}

/// Coerces an argument reference into the [`Arg`](struct.Arg.html)
/// type.
///
/// This is used to wrap each argument pointer before passing them
/// to [`Cif::call`](struct.Cif.html#method.call).
/// (This is the same as [`Arg::new`](struct.Arg.html#method.new)).
pub fn arg<T>(r: &T) -> Arg {
    Arg::new(r)
}

/// Describes the calling convention and types for calling a function.
///
/// This is the `middle` layer’s wrapping of the `low` and `raw` layers’
/// [`ffi_cif`](../raw/struct.ffi_cif.html). An initialized CIF contains
/// references to an array of argument types and a result type, each of
/// which may be allocated on the heap. `Cif` manages the memory of
/// those referenced objects.
///
/// Construct with [`Cif::new`](#method.new) or
/// [`Cif::from_type_array`](#method.from_type_array).
///
/// # Example
///
/// ```
/// extern "C" fn add(x: f64, y: &f64) -> f64 {
///     return x + y;
/// }
///
/// use libffi::middle::*;
///
/// let args = vec![Type::f64(), Type::pointer()];
/// let cif = Cif::new(args.into_iter(), Type::f64());
///
/// let n = unsafe { cif.call(CodePtr(add as _), &[arg(&5), arg(&&6)]) };
/// assert_eq!(11, n);
/// ```
#[derive(Clone, Debug)]
pub struct Cif {
    cif:    low::ffi_cif,
    args:   types::TypeArray,
    result: Type,
}

impl Cif {
    /// Creates a new CIF for the given argument and result types.
    ///
    /// Takes ownership of the argument and result
    /// [`Type`](types/struct.Type.html)s, because the resulting
    /// `Cif` retains references to them.
    /// Defaults to the platform’s default calling convention; this
    /// can be adjusted using [`set_abi`](#method.set_abi).
    pub fn new<I>(args: I, result: Type) -> Self
        where I: ExactSizeIterator<Item=Type>
    {
        Self::from_type_array(types::TypeArray::new(args), result)
    }

    /// Calls a function with the given arguments.
    ///
    /// In particular, this method invokes function `fun` passing it
    /// arguments `args`, and returns the result.
    ///
    /// # Safety
    ///
    /// There is no checking that the calling convention and types
    /// in the `Cif` match the actual calling convention and type of
    /// `fun`.
    pub unsafe fn call<R>(&self, fun: CodePtr, args: &[Arg]) -> R {
        use std::mem;

        assert!(self.cif.nargs as usize == args.len(),
                "Cif::call: passed wrong number of arguments");

        low::call::<R>(&self.cif as *const _ as *mut _,
                       fun,
                       mem::transmute::<*const Arg,
                                        *mut *mut c_void>(args.as_ptr()))
    }

    /// Sets the CIF to use the given calling convention.
    pub fn set_abi(&mut self, abi: FfiAbi) {
        self.cif.abi = abi;
    }

    /// Creates a new CIF for the given argument and result types.
    ///
    /// This is just like [`Cif::new`](#method.new), except it takes a
    /// `TypeArray` instead of an `ExactSizeIterator`.
    pub fn from_type_array(args: types::TypeArray, result: Type) -> Self {
        let mut cif: low::ffi_cif = Default::default();

        unsafe {
            low::prep_cif(&mut cif,
                          low::FFI_DEFAULT_ABI,
                          args.len(),
                          result.as_raw_ptr(),
                          args.as_raw_ptr())
        }.expect("low::prep_cif");

        // Note that cif retains references to args and result,
        // which is why we hold onto them here.
        Cif {
            cif:    cif,
            args:   args,
            result: result,
        }
    }

    /// Gets a raw pointer to the underlying
    /// [`ffi_cif`](../low/struct.ffi_cif.html).
    ///
    /// This can be used for passing a `middle::Cif` to functions from the
    /// [`low`](../low/index.html) and [`raw`](../raw/index.html) modules.
    pub fn as_raw_ptr(&self) -> *mut low::ffi_cif {
        &self.cif as *const _ as *mut _
    }
}

/// Represents a closure callable from C.
///
/// A libffi closure captures a `void*` (“userdata”) and passes it to a
/// callback when the code pointer (obtained via
/// [`code_ptr`](#method.code_ptr) is invoked.
#[derive(Debug)]
pub struct Closure<'a> {
    _cif:    Box<Cif>,
    alloc:   *mut ::low::ffi_closure,
    code:    CodePtr,
    _marker: PhantomData<&'a ()>,
}

impl<'a> Drop for Closure<'a> {
    fn drop(&mut self) {
        unsafe {
            low::closure_free(self.alloc);
        }
    }
}

impl<'a> Closure<'a> {
    /// Creates a new closure. The CIF describes the calling convention
    /// for the resulting C function. When called, the C function will
    /// call `callback`, passing along its arguments and the captured
    /// `userdata`.
    pub fn new<U, R>(cif:      Cif,
                     callback: Callback<U, R>,
                     userdata: &'a U) -> Self
    {
        let cif = Box::new(cif);
        let (alloc, code) = low::closure_alloc();

        unsafe {
            low::prep_closure(alloc,
                              cif.as_raw_ptr(),
                              callback,
                              userdata as *const U,
                              code).unwrap();
        }

        Closure {
            _cif:    cif,
            alloc:   alloc,
            code:    code,
            _marker: PhantomData,
        }
    }

    /// Creates a new mutable closure. The CIF describes the calling convention
    /// for the resulting C function. When called, the C function will
    /// call `callback`, passing along its arguments and the captured
    /// `userdata`.
    pub fn new_mut<U, R>(cif:      Cif,
                         callback: CallbackMut<U, R>,
                         userdata: &'a mut U) -> Self
    {
        let cif = Box::new(cif);
        let (alloc, code) = low::closure_alloc();

        unsafe {
            low::prep_closure_mut(alloc,
                                  cif.as_raw_ptr(),
                                  callback,
                                  userdata as *mut U,
                                  code).unwrap();
        }

        Closure {
            _cif:    cif,
            alloc:   alloc,
            code:    code,
            _marker: PhantomData,
        }
    }

    /// Obtains the callable code pointer for a closure. The result
    /// needs to be transmuted to the correct type before it can be called.
    pub fn code_ptr(&self) -> &unsafe extern "C" fn() {
        self.code.as_fun()
    }
}

#[cfg(test)]
mod test {
    use low;
    use super::*;
    use std::mem;
    use std::os::raw::c_void;

    #[test]
    fn call() {
        let cif  = Cif::new(vec![Type::i64(), Type::i64()].into_iter(),
                            Type::i64());
        let f    = |m: i64, n: i64| -> i64 {
            unsafe { cif.call(CodePtr(add_it as *mut c_void),
                              &[arg(&m), arg(&n)]) }
        };

        assert_eq!(12, f(5, 7));
        assert_eq!(13, f(6, 7));
        assert_eq!(15, f(8, 7));
    }

    extern "C" fn add_it(n: i64, m: i64) -> i64 {
        return n + m;
    }

    #[test]
    fn closure() {
        let cif  = Cif::new(vec![Type::u64()].into_iter(), Type::u64());
        let env: u64 = 5;
        let closure = Closure::new(cif, callback, &env);

        unsafe {
            let fun: &unsafe extern "C" fn(u64) -> u64
                = mem::transmute(closure.code_ptr());

            assert_eq!(11, fun(6));
            assert_eq!(12, fun(7));
        }
    }

    unsafe extern "C" fn callback(_cif: &low::ffi_cif,
                                  result: &mut u64,
                                  args: *const *const c_void,
                                  userdata: &u64)
    {
        let args: *const &u64 = mem::transmute(args);
        *result = **args + *userdata;
    }

    #[test]
    fn rust_lambda() {
        let cif = Cif::new(vec![Type::u64(), Type::u64()].into_iter(),
                           Type::u64());
        let env = |x: u64, y: u64| x + y;
        let closure = Closure::new(cif, callback2, &env);

        unsafe {
            let fun: &unsafe extern "C" fn (u64, u64) -> u64
                = mem::transmute(closure.code_ptr());

            assert_eq!(11, fun(5, 6));
        }
    }

    unsafe extern "C" fn callback2<F: Fn(u64, u64) -> u64>
        (_cif: &low::ffi_cif,
         result: &mut u64,
         args: *const *const c_void,
         userdata: &F)
    {
        let args: *const &u64 = mem::transmute(args);
        let arg1 = **args.offset(0);
        let arg2 = **args.offset(1);

        *result = userdata(arg1, arg2);
    }
}
<|endoftext|>


<commit_before>use api::CommandHandle;
use api::WalletHandle;
use api::ErrorCode;
use libc::c_char;
use commands::CommandExecutor;
use commands::Command;
use commands::payments::PaymentsCommand;
use utils::ctypes;
use errors::prelude::*;

/// Builds Indy request for getting sources list for payment address
/// according to this payment method.
///
/// #Params
/// command_handle: Command handle to map callback to caller context.
/// wallet_handle: wallet handle
/// submitter_did: (Optional) DID of request sender
/// payment_address: target payment address
/// from: shift to the next slice of payment sources
///
/// #Returns
/// get_sources_txn_json - Indy request for getting sources list for payment address
/// payment_method - used payment method
#[no_mangle]
pub extern fn indy_build_get_payment_sources_with_from_request(command_handle: CommandHandle,
                                                               wallet_handle: WalletHandle,
                                                               submitter_did: *const c_char,
                                                               payment_address: *const c_char,
                                                               from: i64,
                                                               cb: Option<extern fn(command_handle_: CommandHandle,
                                                                                err: ErrorCode,
                                                                                get_sources_txn_json: *const c_char,
                                                                                payment_method: *const c_char)>) -> ErrorCode {
    trace!("indy_build_get_payment_sources_with_from_request: >>> wallet_handle: {:?}, submitter_did: {:?}, payment_address: {:?}", wallet_handle, submitter_did, payment_address);
    check_useful_opt_c_str!(submitter_did, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(payment_address, ErrorCode::CommonInvalidParam4);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5);

    let from: Option<u64> = if from == -1 { None } else { Some(from) };

    trace!("indy_build_get_payment_sources_with_from_request: entities >>> wallet_handle: {:?}, submitter_did: {:?}, payment_address: {:?}, from: {:?}", wallet_handle, submitter_did, payment_address, from);

    let result =
        CommandExecutor::instance().send(
            Command::Payments(
                PaymentsCommand::BuildGetPaymentSourcesRequest(
                    wallet_handle,
                    submitter_did,
                    payment_address,
                    from,
                    Box::new(move |result| {
                        let (err, get_sources_txn_json, payment_method) = prepare_result_2!(result, String::new(), String::new());
                        trace!("indy_build_get_payment_sources_with_from_request: get_sources_txn_json: {:?}, payment_method: {:?}", get_sources_txn_json, payment_method);
                        let get_sources_txn_json = ctypes::string_to_cstring(get_sources_txn_json);
                        let payment_method = ctypes::string_to_cstring(payment_method);
                        cb(command_handle, err, get_sources_txn_json.as_ptr(), payment_method.as_ptr());
                    }))
            ));

    let res = prepare_result!(result);

    trace!("indy_build_get_payment_sources_with_from_request: <<< res: {:?}", res);

    res
}

/// Parses response for Indy request for getting sources list.
///
/// #Params
/// command_handle: Command handle to map callback to caller context.
/// payment_method: payment method to use.
/// resp_json: response for Indy request for getting sources list
///
/// #Returns
/// next - pointer to the next slice of payment sources
/// sources_json - parsed (payment method and node version agnostic) sources info as json:
///   [{
///      source: <str>, // source input
///      paymentAddress: <str>, //payment address for this source
///      amount: <int>, // amount
///      extra: <str>, // optional data from payment transaction
///   }]
#[no_mangle]
pub extern fn indy_parse_get_payment_sources_with_from_response(command_handle: CommandHandle,
                                                                payment_method: *const c_char,
                                                                resp_json: *const c_char,
                                                                cb: Option<extern fn(command_handle_: CommandHandle,
                                                                                err: ErrorCode,
                                                                                sources_json: *const c_char,
                                                                                next: i64)>) -> ErrorCode {
    trace!("indy_parse_get_payment_sources_with_from_response: >>> payment_method: {:?}, resp_json: {:?}", payment_method, resp_json);
    check_useful_c_str!(payment_method, ErrorCode::CommonInvalidParam2);
    check_useful_c_str!(resp_json, ErrorCode::CommonInvalidParam3);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4);

    trace!("indy_parse_get_payment_sources_with_from_response: entities >>> payment_method: {:?}, resp_json: {:?}", payment_method, resp_json);

    let result =
        CommandExecutor::instance().send(
            Command::Payments(
                PaymentsCommand::ParseGetPaymentSourcesResponse(
                    payment_method,
                    resp_json,
                    Box::new(move |result| {
                        let (err, sources_json, next) = prepare_result_2!(result, String::new(), -1);
                        trace!("indy_parse_get_payment_sources_with_from_response: sources_json: {:?}", sources_json);
                        let sources_json = ctypes::string_to_cstring(sources_json);
                        cb(command_handle, err, sources_json.as_ptr(), next);
                    }))
            ));

    let res = prepare_result!(result);

    trace!("indy_parse_get_payment_sources_with_from_response: <<< res: {:?}", res);

    res
}<commit_msg>Fix types<commit_after>use api::CommandHandle;
use api::WalletHandle;
use api::ErrorCode;
use libc::c_char;
use commands::CommandExecutor;
use commands::Command;
use commands::payments::PaymentsCommand;
use utils::ctypes;
use errors::prelude::*;

/// Builds Indy request for getting sources list for payment address
/// according to this payment method.
///
/// #Params
/// command_handle: Command handle to map callback to caller context.
/// wallet_handle: wallet handle
/// submitter_did: (Optional) DID of request sender
/// payment_address: target payment address
/// from: shift to the next slice of payment sources
///
/// #Returns
/// get_sources_txn_json - Indy request for getting sources list for payment address
/// payment_method - used payment method
#[no_mangle]
pub extern fn indy_build_get_payment_sources_with_from_request(command_handle: CommandHandle,
                                                               wallet_handle: WalletHandle,
                                                               submitter_did: *const c_char,
                                                               payment_address: *const c_char,
                                                               from: i64,
                                                               cb: Option<extern fn(command_handle_: CommandHandle,
                                                                                err: ErrorCode,
                                                                                get_sources_txn_json: *const c_char,
                                                                                payment_method: *const c_char)>) -> ErrorCode {
    trace!("indy_build_get_payment_sources_with_from_request: >>> wallet_handle: {:?}, submitter_did: {:?}, payment_address: {:?}", wallet_handle, submitter_did, payment_address);
    check_useful_opt_c_str!(submitter_did, ErrorCode::CommonInvalidParam3);
    check_useful_c_str!(payment_address, ErrorCode::CommonInvalidParam4);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5);

    let from: Option<i64> = if from == -1 { None } else { Some(from) };

    trace!("indy_build_get_payment_sources_with_from_request: entities >>> wallet_handle: {:?}, submitter_did: {:?}, payment_address: {:?}, from: {:?}", wallet_handle, submitter_did, payment_address, from);

    let result =
        CommandExecutor::instance().send(
            Command::Payments(
                PaymentsCommand::BuildGetPaymentSourcesRequest(
                    wallet_handle,
                    submitter_did,
                    payment_address,
                    from,
                    Box::new(move |result| {
                        let (err, get_sources_txn_json, payment_method) = prepare_result_2!(result, String::new(), String::new());
                        trace!("indy_build_get_payment_sources_with_from_request: get_sources_txn_json: {:?}, payment_method: {:?}", get_sources_txn_json, payment_method);
                        let get_sources_txn_json = ctypes::string_to_cstring(get_sources_txn_json);
                        let payment_method = ctypes::string_to_cstring(payment_method);
                        cb(command_handle, err, get_sources_txn_json.as_ptr(), payment_method.as_ptr());
                    }))
            ));

    let res = prepare_result!(result);

    trace!("indy_build_get_payment_sources_with_from_request: <<< res: {:?}", res);

    res
}

/// Parses response for Indy request for getting sources list.
///
/// #Params
/// command_handle: Command handle to map callback to caller context.
/// payment_method: payment method to use.
/// resp_json: response for Indy request for getting sources list
///
/// #Returns
/// next - pointer to the next slice of payment sources
/// sources_json - parsed (payment method and node version agnostic) sources info as json:
///   [{
///      source: <str>, // source input
///      paymentAddress: <str>, //payment address for this source
///      amount: <int>, // amount
///      extra: <str>, // optional data from payment transaction
///   }]
#[no_mangle]
pub extern fn indy_parse_get_payment_sources_with_from_response(command_handle: CommandHandle,
                                                                payment_method: *const c_char,
                                                                resp_json: *const c_char,
                                                                cb: Option<extern fn(command_handle_: CommandHandle,
                                                                                err: ErrorCode,
                                                                                sources_json: *const c_char,
                                                                                next: i64)>) -> ErrorCode {
    trace!("indy_parse_get_payment_sources_with_from_response: >>> payment_method: {:?}, resp_json: {:?}", payment_method, resp_json);
    check_useful_c_str!(payment_method, ErrorCode::CommonInvalidParam2);
    check_useful_c_str!(resp_json, ErrorCode::CommonInvalidParam3);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4);

    trace!("indy_parse_get_payment_sources_with_from_response: entities >>> payment_method: {:?}, resp_json: {:?}", payment_method, resp_json);

    let result =
        CommandExecutor::instance().send(
            Command::Payments(
                PaymentsCommand::ParseGetPaymentSourcesResponse(
                    payment_method,
                    resp_json,
                    Box::new(move |result| {
                        let (err, sources_json, next) = prepare_result_2!(result, String::new(), -1);
                        trace!("indy_parse_get_payment_sources_with_from_response: sources_json: {:?}", sources_json);
                        let sources_json = ctypes::string_to_cstring(sources_json);
                        cb(command_handle, err, sources_json.as_ptr(), next);
                    }))
            ));

    let res = prepare_result!(result);

    trace!("indy_parse_get_payment_sources_with_from_response: <<< res: {:?}", res);

    res
}<|endoftext|>


<commit_before>//! The types modules describes all the structures to express FITS files.

struct KeywordRecord {
    keyword: Keyword,
}

#[allow(non_camel_case_types)]
enum Keyword {
    SIMPLE,
    BITPIX,
    NAXIS,
    NAXISn(u8),
    EXTEND,
    NEXTEND,
    EXTVER,
    ORIGIN,
    DATE,
    CREATOR,
    PROCVER,
    FILEVER,
    TIMVERSN,
    TELESCOP,
    INSTRUME,
    OBJECT,
    KEPLERID,
    CHANNEL,
    MODULE,
    OUTPUT,
    CAMPAIGN,
    DATA_REL,
    OBSMODE,
    MISSION,
    TTABLEID,
    RADESYS,
    RA_OBJ,
    DEC_OBJ,
    EQUINOX,
    PMRA,
    PMDEC,
    PMTOTAL,
    PARALLAX,
    GLON,
    GLAT,
    GMAG,
    RMAG,
    IMAG,
    ZMAG,
    JMAG,
    HMAG,
    KMAG,
    KEPMAG,
    GRCOLOR,
    JKCOLOR,
    GKCOLOR,
    TEFF,
    LOGG,
    FEH,
    EBMINUSV,
    AV,
    RADIUS,
    TMINDEX,
    CHECKSUM,
    DATASUM,
    END

}
<commit_msg>Parse Keyword from str<commit_after>//! The types modules describes all the structures to express FITS files.

use std::str::FromStr;

struct KeywordRecord {
    keyword: Keyword,
}

#[derive(Debug, PartialEq)]
#[allow(non_camel_case_types)]
enum Keyword {
    SIMPLE,
    BITPIX,
    NAXIS,
    NAXISn(u8),
    EXTEND,
    NEXTEND,
    EXTVER,
    ORIGIN,
    DATE,
    CREATOR,
    PROCVER,
    FILEVER,
    TIMVERSN,
    TELESCOP,
    INSTRUME,
    OBJECT,
    KEPLERID,
    CHANNEL,
    MODULE,
    OUTPUT,
    CAMPAIGN,
    DATA_REL,
    OBSMODE,
    MISSION,
    TTABLEID,
    RADESYS,
    RA_OBJ,
    DEC_OBJ,
    EQUINOX,
    PMRA,
    PMDEC,
    PMTOTAL,
    PARALLAX,
    GLON,
    GLAT,
    GMAG,
    RMAG,
    IMAG,
    ZMAG,
    JMAG,
    HMAG,
    KMAG,
    KEPMAG,
    GRCOLOR,
    JKCOLOR,
    GKCOLOR,
    TEFF,
    LOGG,
    FEH,
    EBMINUSV,
    AV,
    RADIUS,
    TMINDEX,
    CHECKSUM,
    DATASUM,
    END,
}

#[derive(Debug)]
enum ParseKeywordError {
    UnknownKeyword
}

impl FromStr for Keyword {
    type Err = ParseKeywordError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        // TODO parse NAXIS1 correctly
        match s.trim_right() {
            "SIMPLE" => Ok(Keyword::SIMPLE),
            "BITPIX" => Ok(Keyword::BITPIX),
            "NAXIS" => Ok(Keyword::NAXIS),
            "EXTEND" => Ok(Keyword::EXTEND),
            "NEXTEND" => Ok(Keyword::NEXTEND),
            "EXTVER" => Ok(Keyword::EXTVER),
            "ORIGIN" => Ok(Keyword::ORIGIN),
            "DATE" => Ok(Keyword::DATE),
            "CREATOR" => Ok(Keyword::CREATOR),
            "PROCVER" => Ok(Keyword::PROCVER),
            "FILEVER" => Ok(Keyword::FILEVER),
            "TIMVERSN" => Ok(Keyword::TIMVERSN),
            "TELESCOP" => Ok(Keyword::TELESCOP),
            "INSTRUME" => Ok(Keyword::INSTRUME),
            "OBJECT" => Ok(Keyword::OBJECT),
            "KEPLERID" => Ok(Keyword::KEPLERID),
            "CHANNEL" => Ok(Keyword::CHANNEL),
            "MODULE" => Ok(Keyword::MODULE),
            "OUTPUT" => Ok(Keyword::OUTPUT),
            "CAMPAIGN" => Ok(Keyword::CAMPAIGN),
            "DATA_REL" => Ok(Keyword::DATA_REL),
            "OBSMODE" => Ok(Keyword::OBSMODE),
            "MISSION" => Ok(Keyword::MISSION),
            "TTABLEID" => Ok(Keyword::TTABLEID),
            "RADESYS" => Ok(Keyword::RADESYS),
            "RA_OBJ" => Ok(Keyword::RA_OBJ),
            "DEC_OBJ" => Ok(Keyword::DEC_OBJ),
            "EQUINOX" => Ok(Keyword::EQUINOX),
            "PMRA" => Ok(Keyword::PMRA),
            "PMDEC" => Ok(Keyword::PMDEC),
            "PMTOTAL" => Ok(Keyword::PMTOTAL),
            "PARALLAX" => Ok(Keyword::PARALLAX),
            "GLON" => Ok(Keyword::GLON),
            "GLAT" => Ok(Keyword::GLAT),
            "GMAG" => Ok(Keyword::GMAG),
            "RMAG" => Ok(Keyword::RMAG),
            "IMAG" => Ok(Keyword::IMAG),
            "ZMAG" => Ok(Keyword::ZMAG),
            "JMAG" => Ok(Keyword::JMAG),
            "HMAG" => Ok(Keyword::HMAG),
            "KMAG" => Ok(Keyword::KMAG),
            "KEPMAG" => Ok(Keyword::KEPMAG),
            "GRCOLOR" => Ok(Keyword::GRCOLOR),
            "JKCOLOR" => Ok(Keyword::JKCOLOR),
            "GKCOLOR" => Ok(Keyword::GKCOLOR),
            "TEFF" => Ok(Keyword::TEFF),
            "LOGG" => Ok(Keyword::LOGG),
            "FEH" => Ok(Keyword::FEH),
            "EBMINUSV" => Ok(Keyword::EBMINUSV),
            "AV" => Ok(Keyword::AV),
            "RADIUS" => Ok(Keyword::RADIUS),
            "TMINDEX" => Ok(Keyword::TMINDEX),
            "CHECKSUM" => Ok(Keyword::CHECKSUM),
            "DATASUM" => Ok(Keyword::DATASUM),
            "END" => Ok(Keyword::END),
            _ => Err(ParseKeywordError::UnknownKeyword)
        }
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;
    use super::Keyword;

    #[test]
    fn keywords_could_be_constructed_from_str() {
        let data = vec!(
            ("SIMPLE", Keyword::SIMPLE),
            ("BITPIX", Keyword::BITPIX),
            ("NAXIS", Keyword::NAXIS),
            ("EXTEND", Keyword::EXTEND),
            ("NEXTEND", Keyword::NEXTEND),
            ("EXTVER", Keyword::EXTVER),
            ("ORIGIN", Keyword::ORIGIN),
            ("DATE", Keyword::DATE),
            ("CREATOR", Keyword::CREATOR),
            ("PROCVER", Keyword::PROCVER),
            ("FILEVER", Keyword::FILEVER),
            ("TIMVERSN", Keyword::TIMVERSN),
            ("TELESCOP", Keyword::TELESCOP),
            ("INSTRUME", Keyword::INSTRUME),
            ("OBJECT", Keyword::OBJECT),
            ("KEPLERID", Keyword::KEPLERID),
            ("CHANNEL", Keyword::CHANNEL),
            ("MODULE", Keyword::MODULE),
            ("OUTPUT", Keyword::OUTPUT),
            ("CAMPAIGN", Keyword::CAMPAIGN),
            ("DATA_REL", Keyword::DATA_REL),
            ("OBSMODE", Keyword::OBSMODE),
            ("MISSION", Keyword::MISSION),
            ("TTABLEID", Keyword::TTABLEID),
            ("RADESYS", Keyword::RADESYS),
            ("RA_OBJ", Keyword::RA_OBJ),
            ("DEC_OBJ", Keyword::DEC_OBJ),
            ("EQUINOX", Keyword::EQUINOX),
            ("PMRA", Keyword::PMRA),
            ("PMDEC", Keyword::PMDEC),
            ("PMTOTAL", Keyword::PMTOTAL),
            ("PARALLAX", Keyword::PARALLAX),
            ("GLON", Keyword::GLON),
            ("GLAT", Keyword::GLAT),
            ("GMAG", Keyword::GMAG),
            ("RMAG", Keyword::RMAG),
            ("IMAG", Keyword::IMAG),
            ("ZMAG", Keyword::ZMAG),
            ("JMAG", Keyword::JMAG),
            ("HMAG", Keyword::HMAG),
            ("KMAG", Keyword::KMAG),
            ("KEPMAG", Keyword::KEPMAG),
            ("GRCOLOR", Keyword::GRCOLOR),
            ("JKCOLOR", Keyword::JKCOLOR),
            ("GKCOLOR", Keyword::GKCOLOR),
            ("TEFF", Keyword::TEFF),
            ("LOGG", Keyword::LOGG),
            ("FEH", Keyword::FEH),
            ("EBMINUSV", Keyword::EBMINUSV),
            ("AV", Keyword::AV),
            ("RADIUS", Keyword::RADIUS),
            ("TMINDEX", Keyword::TMINDEX),
            ("CHECKSUM", Keyword::CHECKSUM),
            ("DATASUM", Keyword::DATASUM),
            ("END", Keyword::END),
        );

        for (input, expected) in data {
            assert_eq!(Keyword::from_str(input).unwrap(), expected);
        }
    }

    #[test]
    fn should_also_parse_whitespace_keywords() {
        assert_eq!(Keyword::from_str("SIMPLE  ").unwrap(), Keyword::SIMPLE);
    }
}
<|endoftext|>


<commit_before>use pbr::{ProgressBar, Pipe, MultiBar, Units};
use std::io::Stdout;
use std::sync::Mutex;
use std::thread;
use std::time::Duration;

lazy_static! {
    static ref TOTALS: Mutex<Vec<u64>> = Mutex::new(vec![]);
    static ref PBRS: Mutex<Vec<ProgressBar<Pipe>>> = Mutex::new(vec![]);
}

pub fn start_pbr(file_name: String, lengths: Vec<u64>) {
    let mut mb = MultiBar::new();
    mb.println(&format!("Downloading: {}", file_name));

    let total_length = lengths.iter().fold(0, |a, &b| a + b);
    build_global_bar(&mut mb, total_length);
    mb.println("");

    for length in lengths {
        build_child_bar(&mut mb, length);
    }

    thread::spawn(move || mb.listen());
}

pub fn setting_up_bar(bar: usize) {
    let mut pbrs = PBRS.lock().expect("Failed to aquire PBRS lock, lock poisoned!");
    pbrs[bar + 1].message("Starting... ");
    pbrs[bar + 1].tick();
}

pub fn start_bar(bar: usize) {
    let mut pbrs = PBRS.lock().expect("Failed to aquire PBRS lock, lock poisoned!");
    pbrs[bar + 1].message("");
    pbrs[bar + 1].show_message = false;
    pbrs[bar + 1].tick();
}

pub fn update_bar(bar: usize, progress: u64) {
    let mut pbrs = PBRS.lock().expect("Failed to aquire PBRS lock, lock poisoned!");
    let mut totals = TOTALS.lock().expect("Failed to aquire TOTALS lock, lock poisoned!");

    pbrs[bar + 1].set(progress);
    totals[bar] = progress;

    let total_progress = totals.iter().fold(0, |a, &b| a + b);
    pbrs[0].set(total_progress);
}

pub fn success_global_bar() {
    finish_bar_with_message(0, "Download Complete!");
}

pub fn success_bar(bar: usize) {
    finish_bar_with_message(bar + 1, "Download Complete!");
}

pub fn fail_bar(bar: usize) {
    finish_bar_with_message(bar + 1, "Download Failed!");
}

fn finish_bar_with_message(act_bar: usize, message: &str) {
    PBRS.lock().expect("Failed to aquire PBRS lock, lock poisoned!")[act_bar].finish_print(message);
}

fn build_global_bar(mb: &mut MultiBar<Stdout>, size: u64) {
    let mut pbrs = PBRS.lock().expect("Failed to aquire PBRS lock, lock poisoned!");
    let mut pb = build_bar(mb, size);
    pb.show_message = false;
    pbrs.push(pb);
}

fn build_child_bar(mb: &mut MultiBar<Stdout>, size: u64) {
    let mut pbrs = PBRS.lock().expect("Failed to aquire PBRS lock, lock poisoned!");
    let mut totals = TOTALS.lock().expect("Failed to aquire TOTALS lock, lock poisoned!");
    let mut pb = build_bar(mb, size);
    pb.show_message = true;
    pb.message("Pending... ");
    pbrs.push(pb);
    totals.push(0);
}

fn build_bar(mb: &mut MultiBar<Stdout>, size: u64) -> ProgressBar<Pipe> {
    let mut pb = mb.create_bar(size);
    pb.set_max_refresh_rate(Some(Duration::from_millis(200)));
    pb.tick_format("▏▎▍▌▋▊▉██▉▊▋▌▍▎▏");
    pb.set_units(Units::Bytes);
    pb.tick();
    pb
}
<commit_msg>Tick progress bar after setting message<commit_after>use pbr::{ProgressBar, Pipe, MultiBar, Units};
use std::io::Stdout;
use std::sync::Mutex;
use std::thread;
use std::time::Duration;

lazy_static! {
    static ref TOTALS: Mutex<Vec<u64>> = Mutex::new(vec![]);
    static ref PBRS: Mutex<Vec<ProgressBar<Pipe>>> = Mutex::new(vec![]);
}

pub fn start_pbr(file_name: String, lengths: Vec<u64>) {
    let mut mb = MultiBar::new();
    mb.println(&format!("Downloading: {}", file_name));

    let total_length = lengths.iter().fold(0, |a, &b| a + b);
    build_global_bar(&mut mb, total_length);
    mb.println("");

    for length in lengths {
        build_child_bar(&mut mb, length);
    }

    thread::spawn(move || mb.listen());
}

pub fn setting_up_bar(bar: usize) {
    let mut pbrs = PBRS.lock().expect("Failed to aquire PBRS lock, lock poisoned!");
    pbrs[bar + 1].message("Starting... ");
    pbrs[bar + 1].tick();
}

pub fn start_bar(bar: usize) {
    let mut pbrs = PBRS.lock().expect("Failed to aquire PBRS lock, lock poisoned!");
    pbrs[bar + 1].message("");
    pbrs[bar + 1].show_message = false;
    pbrs[bar + 1].tick();
}

pub fn update_bar(bar: usize, progress: u64) {
    let mut pbrs = PBRS.lock().expect("Failed to aquire PBRS lock, lock poisoned!");
    let mut totals = TOTALS.lock().expect("Failed to aquire TOTALS lock, lock poisoned!");

    pbrs[bar + 1].set(progress);
    totals[bar] = progress;

    let total_progress = totals.iter().fold(0, |a, &b| a + b);
    pbrs[0].set(total_progress);
}

pub fn success_global_bar() {
    finish_bar_with_message(0, "Download Complete!");
}

pub fn success_bar(bar: usize) {
    finish_bar_with_message(bar + 1, "Download Complete!");
}

pub fn fail_bar(bar: usize) {
    finish_bar_with_message(bar + 1, "Download Failed!");
}

fn finish_bar_with_message(act_bar: usize, message: &str) {
    PBRS.lock().expect("Failed to aquire PBRS lock, lock poisoned!")[act_bar].finish_print(message);
}

fn build_global_bar(mb: &mut MultiBar<Stdout>, size: u64) {
    build_bar(mb, size, None);
}

fn build_child_bar(mb: &mut MultiBar<Stdout>, size: u64) {
    build_bar(mb, size, Some("Pending... ".to_string()));

    let mut totals = TOTALS.lock().expect("Failed to aquire TOTALS lock, lock poisoned!");
    totals.push(0);
}

fn build_bar(mb: &mut MultiBar<Stdout>, size: u64, message: Option<String>) {
    let mut pbrs = PBRS.lock().expect("Failed to aquire PBRS lock, lock poisoned!");
    let mut pb = mb.create_bar(size);
    pb.set_max_refresh_rate(Some(Duration::from_millis(200)));
    pb.tick_format("▏▎▍▌▋▊▉██▉▊▋▌▍▎▏");
    pb.set_units(Units::Bytes);

    if let Some(msg) = message {
        pb.show_message = true;
        pb.message(&msg);
    } else {
        pb.show_message = false;
    }

    pb.tick();
    pbrs.push(pb);
}
<|endoftext|>


<commit_before>//! A simple adaptive threadpool that returns a oneshot future.

use log::warn;

use super::OneShot;

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> OneShot<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    // On windows, linux, and macos send it to a threadpool.
    // Otherwise just execute it immediately, because we may
    // not support threads at all!
    #[cfg(not(any(windows, target_os = "linux", target_os = "macos")))]
    {
        (task)();
        return promise;
    }

    #[cfg(any(windows, target_os = "linux", target_os = "macos"))]
    {
        use std::sync::atomic::{AtomicU64, Ordering};
        use std::thread;
        use std::time::Duration;

        use crossbeam_channel::{bounded, Receiver, Sender};

        use crate::{debug_delay, Lazy};

        const MAX_THREADS: u64 = 128;

        static DYNAMIC_THREAD_COUNT: AtomicU64 = AtomicU64::new(0);

        struct Pool {
            sender: Sender<Box<dyn FnOnce() + Send + 'static>>,
            receiver: Receiver<Box<dyn FnOnce() + Send + 'static>>,
        }

        static POOL: Lazy<Pool, fn() -> Pool> = Lazy::new(init_pool);

        fn init_pool() -> Pool {
            for _ in 0..2 {
                let _handle = thread::Builder::new()
                    .name("sled-io".to_string())
                    .spawn(|| {
                        for task in &POOL.receiver {
                            debug_delay();
                            (task)()
                        }
                    })
                    .expect("cannot start a thread driving blocking tasks");
            }

            // We want to use an unbuffered channel here to help
            // us drive our dynamic control. In effect, the
            // kernel's scheduler becomes the queue, reducing
            // the number of buffers that work must flow through
            // before being acted on by a core. This helps keep
            // latency snappy in the overall async system by
            // reducing bufferbloat.
            let (sender, receiver) = bounded(0);
            Pool { sender, receiver }
        }

        // Create up to MAX_THREADS dynamic blocking task worker threads.
        // Dynamic threads will terminate themselves if they don't
        // receive any work after one second.
        fn maybe_create_another_blocking_thread() {
            // We use a `Relaxed` atomic operation because
            // it's just a heuristic, and would not lose correctness
            // even if it's random.
            let workers = DYNAMIC_THREAD_COUNT.load(Ordering::Relaxed);
            if workers >= MAX_THREADS {
                return;
            }

            let spawn_res = thread::Builder::new()
                .name("sled-io".to_string())
                .spawn(|| {
                    let wait_limit = Duration::from_secs(1);

                    let _ =
                        DYNAMIC_THREAD_COUNT.fetch_add(1, Ordering::Relaxed);
                    while let Ok(task) = POOL.receiver.recv_timeout(wait_limit)
                    {
                        debug_delay();
                        (task)();
                    }
                    let _ =
                        DYNAMIC_THREAD_COUNT.fetch_sub(1, Ordering::Relaxed);
                });

            if let Err(e) = spawn_res {
                warn!(
                    "Failed to dynamically increase the threadpool size: {:?}. \
                     Currently have {} dynamic threads",
                    e,
                    workers
                );
            }
        }

        let first_try_result = POOL.sender.try_send(Box::new(task));
        match first_try_result {
            Ok(()) => {
                // NICEEEE
            }
            Err(crossbeam_channel::TrySendError::Full(task)) => {
                // We were not able to send to the channel without
                // blocking. Try to spin up another thread and then
                // retry sending while blocking.
                maybe_create_another_blocking_thread();
                POOL.sender.send(task).unwrap()
            }
            Err(crossbeam_channel::TrySendError::Disconnected(_)) => {
                panic!(
                    "unable to send to blocking threadpool \
                     due to receiver disconnection"
                );
            }
        }

        promise
    }
}
<commit_msg>Fix log warning<commit_after>//! A simple adaptive threadpool that returns a oneshot future.

use super::OneShot;

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> OneShot<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    // On windows, linux, and macos send it to a threadpool.
    // Otherwise just execute it immediately, because we may
    // not support threads at all!
    #[cfg(not(any(windows, target_os = "linux", target_os = "macos")))]
    {
        (task)();
        return promise;
    }

    #[cfg(any(windows, target_os = "linux", target_os = "macos"))]
    {
        use std::sync::atomic::{AtomicU64, Ordering};
        use std::thread;
        use std::time::Duration;

        use crossbeam_channel::{bounded, Receiver, Sender};

        use crate::{debug_delay, Lazy};

        const MAX_THREADS: u64 = 128;

        static DYNAMIC_THREAD_COUNT: AtomicU64 = AtomicU64::new(0);

        struct Pool {
            sender: Sender<Box<dyn FnOnce() + Send + 'static>>,
            receiver: Receiver<Box<dyn FnOnce() + Send + 'static>>,
        }

        static POOL: Lazy<Pool, fn() -> Pool> = Lazy::new(init_pool);

        fn init_pool() -> Pool {
            for _ in 0..2 {
                let _handle = thread::Builder::new()
                    .name("sled-io".to_string())
                    .spawn(|| {
                        for task in &POOL.receiver {
                            debug_delay();
                            (task)()
                        }
                    })
                    .expect("cannot start a thread driving blocking tasks");
            }

            // We want to use an unbuffered channel here to help
            // us drive our dynamic control. In effect, the
            // kernel's scheduler becomes the queue, reducing
            // the number of buffers that work must flow through
            // before being acted on by a core. This helps keep
            // latency snappy in the overall async system by
            // reducing bufferbloat.
            let (sender, receiver) = bounded(0);
            Pool { sender, receiver }
        }

        // Create up to MAX_THREADS dynamic blocking task worker threads.
        // Dynamic threads will terminate themselves if they don't
        // receive any work after one second.
        fn maybe_create_another_blocking_thread() {
            // We use a `Relaxed` atomic operation because
            // it's just a heuristic, and would not lose correctness
            // even if it's random.
            let workers = DYNAMIC_THREAD_COUNT.load(Ordering::Relaxed);
            if workers >= MAX_THREADS {
                return;
            }

            let spawn_res = thread::Builder::new()
                .name("sled-io".to_string())
                .spawn(|| {
                    let wait_limit = Duration::from_secs(1);

                    let _ =
                        DYNAMIC_THREAD_COUNT.fetch_add(1, Ordering::Relaxed);
                    while let Ok(task) = POOL.receiver.recv_timeout(wait_limit)
                    {
                        debug_delay();
                        (task)();
                    }
                    let _ =
                        DYNAMIC_THREAD_COUNT.fetch_sub(1, Ordering::Relaxed);
                });

            if let Err(e) = spawn_res {
                log::warn!(
                    "Failed to dynamically increase the threadpool size: {:?}. \
                     Currently have {} dynamic threads",
                    e,
                    workers
                );
            }
        }

        let first_try_result = POOL.sender.try_send(Box::new(task));
        match first_try_result {
            Ok(()) => {
                // NICEEEE
            }
            Err(crossbeam_channel::TrySendError::Full(task)) => {
                // We were not able to send to the channel without
                // blocking. Try to spin up another thread and then
                // retry sending while blocking.
                maybe_create_another_blocking_thread();
                POOL.sender.send(task).unwrap()
            }
            Err(crossbeam_channel::TrySendError::Disconnected(_)) => {
                panic!(
                    "unable to send to blocking threadpool \
                     due to receiver disconnection"
                );
            }
        }

        promise
    }
}
<|endoftext|>