<commit_before>use std::ops::{Mul, Add};

use rand::{Rand, Rng, Closed01};
use num::{Float, Zero};

use rblas::{Gemm, Matrix};
use rblas::attribute::Transpose;

use ndarray::{ArrayBase, DataOwned, DataMut};
use ndarray::blas::{BlasArrayViewMut, AsBlas};

use helpers::random01;

pub trait ShapeAsTuple<T> {
    fn shape_as_tuple(&self) -> T;
}

pub type FloatT = f32;

impl<T> ShapeAsTuple<(usize, usize)> for ArrayBase<Vec<T>, (usize, usize)> {
    #[inline]
    fn shape_as_tuple(&self) -> (usize, usize) {
        (self.shape()[0], self.shape()[1])
    }
}

pub type Ix = (usize, usize);
pub type MyMatrix = ArrayBase<Vec<FloatT>, Ix>;

// TODO call this OrthoNMFBlas
pub struct OrthogonalNMFBlas {
    pub hidden: MyMatrix,
    pub weights: MyMatrix,

    // these hold temporary results during an iteration.
    // kept in this struct to prevent unnecessary memory allocations.
    pub weights_dividend: MyMatrix,
    pub weights_divisor: MyMatrix,
    pub weights_divisor_reconstruction: MyMatrix,

    pub hidden_dividend: MyMatrix,
    pub hidden_divisor: MyMatrix,
    pub hidden_divisor_partial: MyMatrix,

    pub gamma: MyMatrix,
}

impl OrthogonalNMFBlas
    // where FloatT: 'a + Float + Mul + Zero + Clone + Gemm,
          // ArrayBase<Vec<FloatT>, (usize, usize)>: 'a + AsBlas<FloatT, ArrayBase<Vec<FloatT>, (usize, usize)>, (usize, usize)> + DataOwned<Elem=FloatT> + DataMut<Elem=FloatT>,
          // BlasArrayViewMut<'a, FloatT, (usize, usize)>: Matrix<FloatT>,
          // Closed01<FloatT>: Rand
{
    pub fn init_random01<R: Rng>(nhidden: usize, nobserved: usize, nsamples: usize, rng: &mut R) -> OrthogonalNMFBlas {
        let mut hidden = MyMatrix::zeros((nhidden, nobserved));
        for x in hidden.iter_mut() {
            *x = random01(rng);
        }

        let mut weights = MyMatrix::zeros((nsamples, nhidden));
        for x in weights.iter_mut() {
            *x = random01(rng);
        }

        Self::init(hidden, weights)
    }

    // TODO initialize with values from last time step t-1 instead of choosing randomly
    pub fn init(hidden: MyMatrix, weights: MyMatrix) -> OrthogonalNMFBlas {
        let weights_shape = weights.shape_as_tuple();
        let hidden_shape = hidden.shape_as_tuple();

        let nhidden = hidden_shape.0;
        let nobserved = hidden_shape.1;
        let nsamples = weights_shape.0;

        let samples_shape = (nsamples, nobserved);

        OrthogonalNMFBlas {
            hidden: hidden,
            weights: weights,

            weights_dividend: MyMatrix::zeros(weights_shape),
            weights_divisor: MyMatrix::zeros(weights_shape),
            weights_divisor_reconstruction: MyMatrix::zeros(samples_shape),

            hidden_dividend: MyMatrix::zeros(hidden_shape),
            hidden_divisor: MyMatrix::zeros(hidden_shape),
            hidden_divisor_partial: MyMatrix::zeros((nhidden, nhidden)),

            gamma: OrthogonalNMFBlas::gamma(nhidden),
        }
    }

    /// returns the number of observed variables
    #[inline]
    pub fn nobserved(&self) -> usize {
        self.hidden.shape()[1]
    }

    /// returns the number of hidden variables
    #[inline]
    pub fn nhidden(&self) -> usize {
        self.hidden.shape()[0]
    }

    /// returns the number of data points
    #[inline]
    pub fn nsamples(&self) -> usize {
        self.weights.shape()[0]
    }

    pub fn samples_shape(&self) -> (usize, usize) {
        (self.nsamples(), self.nobserved())
    }

    /// gamma is a symetric matrix with diagonal elements equal to zero
    /// and other elements equal to 1
    pub fn gamma(size: usize) -> MyMatrix {
        let mut gamma = MyMatrix::from_elem((size, size), 1.);
        for x in gamma.diag_mut().iter_mut() {
            *x = 0.
        }
        gamma
    }

    /// `samples * hidden.transpose()`
    #[inline]
    pub fn iterate_weights_dividend(&mut self, samples: &mut MyMatrix) {
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &samples.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.weights_dividend.blas());

    }

    /// `weights * hidden * hidden.transpose()`
    #[inline]
    pub fn iterate_weights_divisor(&mut self) {
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.weights.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            &0.,
            &mut self.weights_divisor_reconstruction.blas());
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.weights_divisor_reconstruction.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.weights_divisor.blas());
    }

    /// `weights.transpose() * samples`
    #[inline]
    pub fn iterate_hidden_dividend(&mut self, samples: &mut MyMatrix) {
        Gemm::gemm(
            &1.,
            Transpose::Trans, &self.weights.blas(),
            Transpose::NoTrans, &samples.blas(),
            &0.,
            &mut self.hidden_dividend.blas());
    }

    /// `weights.transpose() * weights * hidden + alpha * gamma * hidden`
    #[inline]
    pub fn iterate_hidden_divisor(&mut self, alpha: FloatT) {
        // we must make a copy here because we need two mutable
        // references to weights at the same time for .blas()
        // weights_copy.clone_from(&weights);
        // TODO this will be solved once
        // https://github.com/bluss/rust-ndarray/pull/40
        // is merged.
        let mut weights_copy = self.weights.clone();
        Gemm::gemm(
            &1.,
            Transpose::Trans, &self.weights.blas(),
            Transpose::NoTrans, &weights_copy.blas(),
            &0.,
            &mut self.hidden_divisor_partial.blas());
        Gemm::gemm(
            &alpha,
            Transpose::NoTrans, &self.gamma.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            &0.,
            &mut self.hidden_divisor.blas());
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.hidden_divisor_partial.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            // add to previous contents of self.hidden_divisor
            &1.,
            &mut self.hidden_divisor.blas());
    }

    // TODO better name
    // per element division
    /// `result(i,j) <- result(i,j) * dividend(i,j) / divisor(i,j)`
    #[inline]
    pub fn update(
        dividend: &MyMatrix,
        divisor: &MyMatrix,
        result: &mut MyMatrix,
    ) {
        let shape = result.shape_as_tuple();
        assert_eq!(shape, dividend.shape_as_tuple());
        assert_eq!(shape, divisor.shape_as_tuple());

        for row in 0..shape.0 {
            for col in 0..shape.1 {
                let index = (row, col);
                let mut div = unsafe { divisor.uget(index).clone() };
                // if we have any 0 in any of the matrixes
                // self.weights or self.hidden then
                // divisor will be 0.
                // we can't divide by 0.
                // so we change them to the min positive value.
                if FloatT::zero() == div {
                    div = FloatT::min_positive_value();
                }
                unsafe {
                    *result.uget_mut(index) *= dividend.uget(index) / div;
                }
            }
        }
    }

    // TODO consider calling this something like iteration_step
    // TODO how many iterations ?
    // TODO compare this to the seoung solution
    /// it gets better and better with each iteration.
    /// one observed per column.
    /// one sample per row.
    pub fn iterate(&mut self, alpha: FloatT, samples: &mut MyMatrix) {
        assert_eq!(samples.shape_as_tuple(), self.samples_shape());

        self.iterate_weights_dividend(samples);
        self.iterate_weights_divisor();
        self.iterate_hidden_dividend(samples);
        self.iterate_hidden_divisor(alpha);

        OrthogonalNMFBlas::update(
            &self.weights_dividend,
            &self.weights_divisor,
            &mut self.weights);
        OrthogonalNMFBlas::update(
            &self.hidden_dividend,
            &self.hidden_divisor,
            &mut self.hidden);
    }
}
<commit_msg>ortho nmf blas: comments that document iteration steps<commit_after>use std::ops::{Mul, Add};

use rand::{Rand, Rng, Closed01};
use num::{Float, Zero};

use rblas::{Gemm, Matrix};
use rblas::attribute::Transpose;

use ndarray::{ArrayBase, DataOwned, DataMut};
use ndarray::blas::{BlasArrayViewMut, AsBlas};

use helpers::random01;

pub trait ShapeAsTuple<T> {
    fn shape_as_tuple(&self) -> T;
}

pub type FloatT = f32;

impl<T> ShapeAsTuple<(usize, usize)> for ArrayBase<Vec<T>, (usize, usize)> {
    #[inline]
    fn shape_as_tuple(&self) -> (usize, usize) {
        (self.shape()[0], self.shape()[1])
    }
}

pub type Ix = (usize, usize);
pub type MyMatrix = ArrayBase<Vec<FloatT>, Ix>;

// TODO call this OrthoNMFBlas
pub struct OrthogonalNMFBlas {
    pub hidden: MyMatrix,
    pub weights: MyMatrix,

    // these hold temporary results during an iteration.
    // kept in this struct to prevent unnecessary memory allocations.
    pub weights_dividend: MyMatrix,
    pub weights_divisor: MyMatrix,
    pub weights_divisor_reconstruction: MyMatrix,

    pub hidden_dividend: MyMatrix,
    pub hidden_divisor: MyMatrix,
    pub hidden_divisor_partial: MyMatrix,

    pub gamma: MyMatrix,
}

impl OrthogonalNMFBlas
    // where FloatT: 'a + Float + Mul + Zero + Clone + Gemm,
          // ArrayBase<Vec<FloatT>, (usize, usize)>: 'a + AsBlas<FloatT, ArrayBase<Vec<FloatT>, (usize, usize)>, (usize, usize)> + DataOwned<Elem=FloatT> + DataMut<Elem=FloatT>,
          // BlasArrayViewMut<'a, FloatT, (usize, usize)>: Matrix<FloatT>,
          // Closed01<FloatT>: Rand
{
    pub fn init_random01<R: Rng>(nhidden: usize, nobserved: usize, nsamples: usize, rng: &mut R) -> OrthogonalNMFBlas {
        let mut hidden = MyMatrix::zeros((nhidden, nobserved));
        for x in hidden.iter_mut() {
            *x = random01(rng);
        }

        let mut weights = MyMatrix::zeros((nsamples, nhidden));
        for x in weights.iter_mut() {
            *x = random01(rng);
        }

        Self::init(hidden, weights)
    }

    // TODO initialize with values from last time step t-1 instead of choosing randomly
    pub fn init(hidden: MyMatrix, weights: MyMatrix) -> OrthogonalNMFBlas {
        let weights_shape = weights.shape_as_tuple();
        let hidden_shape = hidden.shape_as_tuple();

        let nhidden = hidden_shape.0;
        let nobserved = hidden_shape.1;
        let nsamples = weights_shape.0;

        let samples_shape = (nsamples, nobserved);

        OrthogonalNMFBlas {
            hidden: hidden,
            weights: weights,

            weights_dividend: MyMatrix::zeros(weights_shape),
            weights_divisor: MyMatrix::zeros(weights_shape),
            weights_divisor_reconstruction: MyMatrix::zeros(samples_shape),

            hidden_dividend: MyMatrix::zeros(hidden_shape),
            hidden_divisor: MyMatrix::zeros(hidden_shape),
            hidden_divisor_partial: MyMatrix::zeros((nhidden, nhidden)),

            gamma: OrthogonalNMFBlas::gamma(nhidden),
        }
    }

    /// returns the number of observed variables
    #[inline]
    pub fn nobserved(&self) -> usize {
        self.hidden.shape()[1]
    }

    /// returns the number of hidden variables
    #[inline]
    pub fn nhidden(&self) -> usize {
        self.hidden.shape()[0]
    }

    /// returns the number of data points
    #[inline]
    pub fn nsamples(&self) -> usize {
        self.weights.shape()[0]
    }

    pub fn samples_shape(&self) -> (usize, usize) {
        (self.nsamples(), self.nobserved())
    }

    /// gamma is a symetric matrix with diagonal elements equal to zero
    /// and other elements equal to 1
    pub fn gamma(size: usize) -> MyMatrix {
        let mut gamma = MyMatrix::from_elem((size, size), 1.);
        for x in gamma.diag_mut().iter_mut() {
            *x = 0.
        }
        gamma
    }

    /// `samples * hidden.transpose()`
    #[inline]
    pub fn iterate_weights_dividend(&mut self, samples: &mut MyMatrix) {
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &samples.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.weights_dividend.blas());

    }

    /// `weights * hidden * hidden.transpose()`
    #[inline]
    pub fn iterate_weights_divisor(&mut self) {
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.weights.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            &0.,
            &mut self.weights_divisor_reconstruction.blas());
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.weights_divisor_reconstruction.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.weights_divisor.blas());
    }

    /// `weights.transpose() * samples`
    #[inline]
    pub fn iterate_hidden_dividend(&mut self, samples: &mut MyMatrix) {
        Gemm::gemm(
            &1.,
            Transpose::Trans, &self.weights.blas(),
            Transpose::NoTrans, &samples.blas(),
            &0.,
            &mut self.hidden_dividend.blas());
    }

    /// `weights.transpose() * weights * hidden + alpha * gamma * hidden`
    #[inline]
    pub fn iterate_hidden_divisor(&mut self, alpha: FloatT) {
        // we must make a copy here because we need two mutable
        // references to weights at the same time for .blas()
        // weights_copy.clone_from(&weights);
        // TODO this will be solved once
        // https://github.com/bluss/rust-ndarray/pull/40
        // is merged.
        let mut weights_copy = self.weights.clone();
        Gemm::gemm(
            &1.,
            Transpose::Trans, &self.weights.blas(),
            Transpose::NoTrans, &weights_copy.blas(),
            &0.,
            &mut self.hidden_divisor_partial.blas());
        Gemm::gemm(
            &alpha,
            Transpose::NoTrans, &self.gamma.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            &0.,
            &mut self.hidden_divisor.blas());
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.hidden_divisor_partial.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            // add to previous contents of self.hidden_divisor
            &1.,
            &mut self.hidden_divisor.blas());
    }

    // TODO better name
    // per element division
    /// `result(i,j) <- result(i,j) * dividend(i,j) / divisor(i,j)`
    #[inline]
    pub fn update(
        dividend: &MyMatrix,
        divisor: &MyMatrix,
        result: &mut MyMatrix,
    ) {
        let shape = result.shape_as_tuple();
        assert_eq!(shape, dividend.shape_as_tuple());
        assert_eq!(shape, divisor.shape_as_tuple());

        for row in 0..shape.0 {
            for col in 0..shape.1 {
                let index = (row, col);
                let mut div = unsafe { divisor.uget(index).clone() };
                // if we have any 0 in any of the matrixes
                // self.weights or self.hidden then
                // divisor will be 0.
                // we can't divide by 0.
                // so we change them to the min positive value.
                if FloatT::zero() == div {
                    div = FloatT::min_positive_value();
                }
                unsafe {
                    *result.uget_mut(index) *= dividend.uget(index) / div;
                }
            }
        }
    }

    // TODO consider calling this something like iteration_step
    // TODO how many iterations ?
    // TODO compare this to the seoung solution
    /// it gets better and better with each iteration.
    /// one observed per column.
    /// one sample per row.
    pub fn iterate(&mut self, alpha: FloatT, samples: &mut MyMatrix) {
        assert_eq!(samples.shape_as_tuple(), self.samples_shape());

        // weights_dividend <- samples * hidden.transpose()
        self.iterate_weights_dividend(samples);
        // weights_divisor <- weights * hidden * hidden.transpose()
        self.iterate_weights_divisor();
        // hidden_dividend <- weights.transpose() * samples
        self.iterate_hidden_dividend(samples);
        // hidden_divisor <-
        // weights.transpose() * weights * hidden + alpha * gamma * hidden
        self.iterate_hidden_divisor(alpha);

        // weights(i,j) <-
        // weights(i,j) * weights_dividend(i,j) / weights_divisor(i,j)
        OrthogonalNMFBlas::update(
            &self.weights_dividend,
            &self.weights_divisor,
            &mut self.weights);
        // hidden(i,j) <-
        // hidden(i,j) * hidden_dividend(i,j) / hidden_divisor(i,j)
        OrthogonalNMFBlas::update(
            &self.hidden_dividend,
            &self.hidden_divisor,
            &mut self.hidden);
    }
}
<|endoftext|>


<commit_before>fn main() {
    let mut depth = 0;
    for &c in &include_bytes!("1.in")[..] {
        depth += ((c as i32) << 31 >> 31) | 1;
    }
    println!("{}", depth);
}<commit_msg>Day 1, part 2.<commit_after>fn main() {
    let mut depth = 0;
    for (i, &c) in include_bytes!("1.in").iter().enumerate() {
        depth += ((c as i32) << 31 >> 31) | 1;
        if cfg!(part2) && depth == -1 {
            println!("{}", i + 1);
            return;
        }
    }
    println!("{}", depth);
}<|endoftext|>


<commit_before>use core::libc::{c_char, c_void};
use core::libc::types::common::c99::uint32_t;

#[nolink]
#[link_args="-L../libwapcaplet -lwapcaplet"]
pub extern mod linking { }

<commit_msg>Add definitions of a few data structures that rust-netsurfcss needs<commit_after>use core::libc::{c_char, c_void, size_t};
use core::libc::types::common::c99::uint32_t;

#[nolink]
#[link_args="-L../libwapcaplet -lwapcaplet"]
pub extern mod linking { }

pub type lwc_refcounter = uint32_t;
pub type lwc_hash = uint32_t;

pub struct lwc_string {
    prevptr: **lwc_string,
    next: *lwc_string,
    len: size_t,
    hash: lwc_hash,
    refcnt: lwc_refcounter,
    insensitive: *lwc_string
}
<|endoftext|>


<commit_before>use crate::syntax::Api;
use proc_macro2::Ident;
use std::collections::BTreeMap;

pub struct NamespaceEntries<'a> {
    entries: Vec<&'a Api>,
    children: BTreeMap<&'a Ident, NamespaceEntries<'a>>,
}

impl<'a> NamespaceEntries<'a> {
    pub fn new(apis: &'a [Api]) -> Self {
        let api_refs = apis.iter().collect::<Vec<_>>();
        Self::sort_by_inner_namespace(api_refs, 0)
    }

    pub fn entries(&self) -> &[&'a Api] {
        &self.entries
    }

    pub fn children(&self) -> impl Iterator<Item = (&&Ident, &NamespaceEntries)> {
        self.children.iter()
    }

    fn sort_by_inner_namespace(apis: Vec<&'a Api>, depth: usize) -> Self {
        let mut root = NamespaceEntries {
            entries: Vec::new(),
            children: BTreeMap::new(),
        };

        let mut kids_by_child_ns = BTreeMap::new();
        for api in apis {
            if let Some(ns) = api.get_namespace() {
                let first_ns_elem = ns.iter().nth(depth);
                if let Some(first_ns_elem) = first_ns_elem {
                    let list = kids_by_child_ns.entry(first_ns_elem).or_insert(Vec::new());
                    list.push(api);
                    continue;
                }
            }
            root.entries.push(api);
        }

        for (k, v) in kids_by_child_ns.into_iter() {
            root.children
                .insert(k, Self::sort_by_inner_namespace(v, depth + 1));
        }

        root
    }
}

#[cfg(test)]
mod tests {
    use super::NamespaceEntries;
    use crate::syntax::namespace::Namespace;
    use crate::syntax::{Api, Doc, ExternType, Pair};
    use proc_macro2::{Ident, Span};
    use syn::Token;

    #[test]
    fn test_ns_entries_sort() {
        let entries = vec![
            make_api(None, "C"),
            make_api(None, "A"),
            make_api(Some("G"), "E"),
            make_api(Some("D"), "F"),
            make_api(Some("G"), "H"),
            make_api(Some("D::K"), "L"),
            make_api(Some("D::K"), "M"),
            make_api(None, "B"),
            make_api(Some("D"), "I"),
            make_api(Some("D"), "J"),
        ];
        let ns = NamespaceEntries::new(&entries);
        let root_entries = ns.entries();
        assert_eq!(root_entries.len(), 3);
        assert_ident(root_entries[0], "C");
        assert_ident(root_entries[1], "A");
        assert_ident(root_entries[2], "B");
        let mut kids = ns.children();
        let (d_id, d_nse) = kids.next().unwrap();
        assert_eq!(d_id.to_string(), "D");
        let (g_id, g_nse) = kids.next().unwrap();
        assert_eq!(g_id.to_string(), "G");
        assert!(kids.next().is_none());
        let d_nse_entries = d_nse.entries();
        assert_eq!(d_nse_entries.len(), 3);
        assert_ident(d_nse_entries[0], "F");
        assert_ident(d_nse_entries[1], "I");
        assert_ident(d_nse_entries[2], "J");
        let g_nse_entries = g_nse.entries();
        assert_eq!(g_nse_entries.len(), 2);
        assert_ident(g_nse_entries[0], "E");
        assert_ident(g_nse_entries[1], "H");
        let mut g_kids = g_nse.children();
        assert!(g_kids.next().is_none());
        let mut d_kids = d_nse.children();
        let (k_id, k_nse) = d_kids.next().unwrap();
        assert_eq!(k_id.to_string(), "K");
        let k_nse_entries = k_nse.entries();
        assert_eq!(k_nse_entries.len(), 2);
        assert_ident(k_nse_entries[0], "L");
        assert_ident(k_nse_entries[1], "M");
    }

    fn assert_ident(api: &Api, expected: &str) {
        if let Api::CxxType(cxx_type) = api {
            assert_eq!(cxx_type.ident.cxx.ident.to_string(), expected);
        } else {
            unreachable!()
        }
    }

    fn make_api(ns: Option<&str>, ident: &str) -> Api {
        let ns = match ns {
            Some(st) => Namespace::from_str(st),
            None => Namespace::none(),
        };
        let ident = Pair::new(ns, Ident::new(ident, Span::call_site()));
        Api::CxxType(ExternType {
            doc: Doc::new(),
            type_token: Token![type](Span::call_site()),
            ident,
            semi_token: Token![;](Span::call_site()),
            trusted: true,
        })
    }
}
<commit_msg>Use a less strange return type for NamespaceEntries::children<commit_after>use crate::syntax::Api;
use proc_macro2::Ident;
use std::collections::BTreeMap;

pub struct NamespaceEntries<'a> {
    entries: Vec<&'a Api>,
    children: BTreeMap<&'a Ident, NamespaceEntries<'a>>,
}

impl<'a> NamespaceEntries<'a> {
    pub fn new(apis: &'a [Api]) -> Self {
        let api_refs = apis.iter().collect::<Vec<_>>();
        Self::sort_by_inner_namespace(api_refs, 0)
    }

    pub fn entries(&self) -> &[&'a Api] {
        &self.entries
    }

    pub fn children(&self) -> impl Iterator<Item = (&Ident, &NamespaceEntries)> {
        self.children.iter().map(|(k, entries)| (*k, entries))
    }

    fn sort_by_inner_namespace(apis: Vec<&'a Api>, depth: usize) -> Self {
        let mut root = NamespaceEntries {
            entries: Vec::new(),
            children: BTreeMap::new(),
        };

        let mut kids_by_child_ns = BTreeMap::new();
        for api in apis {
            if let Some(ns) = api.get_namespace() {
                let first_ns_elem = ns.iter().nth(depth);
                if let Some(first_ns_elem) = first_ns_elem {
                    let list = kids_by_child_ns.entry(first_ns_elem).or_insert(Vec::new());
                    list.push(api);
                    continue;
                }
            }
            root.entries.push(api);
        }

        for (k, v) in kids_by_child_ns.into_iter() {
            root.children
                .insert(k, Self::sort_by_inner_namespace(v, depth + 1));
        }

        root
    }
}

#[cfg(test)]
mod tests {
    use super::NamespaceEntries;
    use crate::syntax::namespace::Namespace;
    use crate::syntax::{Api, Doc, ExternType, Pair};
    use proc_macro2::{Ident, Span};
    use syn::Token;

    #[test]
    fn test_ns_entries_sort() {
        let entries = vec![
            make_api(None, "C"),
            make_api(None, "A"),
            make_api(Some("G"), "E"),
            make_api(Some("D"), "F"),
            make_api(Some("G"), "H"),
            make_api(Some("D::K"), "L"),
            make_api(Some("D::K"), "M"),
            make_api(None, "B"),
            make_api(Some("D"), "I"),
            make_api(Some("D"), "J"),
        ];
        let ns = NamespaceEntries::new(&entries);
        let root_entries = ns.entries();
        assert_eq!(root_entries.len(), 3);
        assert_ident(root_entries[0], "C");
        assert_ident(root_entries[1], "A");
        assert_ident(root_entries[2], "B");
        let mut kids = ns.children();
        let (d_id, d_nse) = kids.next().unwrap();
        assert_eq!(d_id.to_string(), "D");
        let (g_id, g_nse) = kids.next().unwrap();
        assert_eq!(g_id.to_string(), "G");
        assert!(kids.next().is_none());
        let d_nse_entries = d_nse.entries();
        assert_eq!(d_nse_entries.len(), 3);
        assert_ident(d_nse_entries[0], "F");
        assert_ident(d_nse_entries[1], "I");
        assert_ident(d_nse_entries[2], "J");
        let g_nse_entries = g_nse.entries();
        assert_eq!(g_nse_entries.len(), 2);
        assert_ident(g_nse_entries[0], "E");
        assert_ident(g_nse_entries[1], "H");
        let mut g_kids = g_nse.children();
        assert!(g_kids.next().is_none());
        let mut d_kids = d_nse.children();
        let (k_id, k_nse) = d_kids.next().unwrap();
        assert_eq!(k_id.to_string(), "K");
        let k_nse_entries = k_nse.entries();
        assert_eq!(k_nse_entries.len(), 2);
        assert_ident(k_nse_entries[0], "L");
        assert_ident(k_nse_entries[1], "M");
    }

    fn assert_ident(api: &Api, expected: &str) {
        if let Api::CxxType(cxx_type) = api {
            assert_eq!(cxx_type.ident.cxx.ident.to_string(), expected);
        } else {
            unreachable!()
        }
    }

    fn make_api(ns: Option<&str>, ident: &str) -> Api {
        let ns = match ns {
            Some(st) => Namespace::from_str(st),
            None => Namespace::none(),
        };
        let ident = Pair::new(ns, Ident::new(ident, Span::call_site()));
        Api::CxxType(ExternType {
            doc: Doc::new(),
            type_token: Token![type](Span::call_site()),
            ident,
            semi_token: Token![;](Span::call_site()),
            trusted: true,
        })
    }
}
<|endoftext|>


<commit_before>use crate::syntax::Api;
use proc_macro2::Ident;
use std::collections::BTreeMap;
use std::iter::FromIterator;

pub struct NamespaceEntries<'a> {
    direct: Vec<&'a Api>,
    nested: BTreeMap<&'a Ident, NamespaceEntries<'a>>,
}

impl<'a> NamespaceEntries<'a> {
    pub fn new(apis: &'a [Api]) -> Self {
        let api_refs = Vec::from_iter(apis);
        Self::sort_by_inner_namespace(api_refs, 0)
    }

    pub fn direct_content(&self) -> &[&'a Api] {
        &self.direct
    }

    pub fn nested_content(&self) -> impl Iterator<Item = (&Ident, &NamespaceEntries)> {
        self.nested.iter().map(|(k, entries)| (*k, entries))
    }

    fn sort_by_inner_namespace(apis: Vec<&'a Api>, depth: usize) -> Self {
        let mut root = NamespaceEntries {
            direct: Vec::new(),
            nested: BTreeMap::new(),
        };

        let mut nested_namespaces = BTreeMap::new();
        for api in apis {
            if let Some(ns) = api.namespace() {
                let first_ns_elem = ns.iter().nth(depth);
                if let Some(first_ns_elem) = first_ns_elem {
                    let list = nested_namespaces.entry(first_ns_elem).or_insert(Vec::new());
                    list.push(api);
                    continue;
                }
            }
            root.direct.push(api);
        }

        for (k, v) in nested_namespaces.into_iter() {
            root.nested
                .insert(k, Self::sort_by_inner_namespace(v, depth + 1));
        }

        root
    }
}

#[cfg(test)]
mod tests {
    use super::NamespaceEntries;
    use crate::syntax::namespace::Namespace;
    use crate::syntax::{Api, Doc, ExternType, Pair};
    use proc_macro2::{Ident, Span};
    use syn::Token;

    #[test]
    fn test_ns_entries_sort() {
        let entries = vec![
            make_api(None, "C"),
            make_api(None, "A"),
            make_api(Some("G"), "E"),
            make_api(Some("D"), "F"),
            make_api(Some("G"), "H"),
            make_api(Some("D::K"), "L"),
            make_api(Some("D::K"), "M"),
            make_api(None, "B"),
            make_api(Some("D"), "I"),
            make_api(Some("D"), "J"),
        ];
        let ns = NamespaceEntries::new(&entries);
        let root_entries = ns.direct_content();
        assert_eq!(root_entries.len(), 3);
        assert_ident(root_entries[0], "C");
        assert_ident(root_entries[1], "A");
        assert_ident(root_entries[2], "B");
        let mut kids = ns.nested_content();
        let (d_id, d_nse) = kids.next().unwrap();
        assert_eq!(d_id.to_string(), "D");
        let (g_id, g_nse) = kids.next().unwrap();
        assert_eq!(g_id.to_string(), "G");
        assert!(kids.next().is_none());
        let d_nse_entries = d_nse.direct_content();
        assert_eq!(d_nse_entries.len(), 3);
        assert_ident(d_nse_entries[0], "F");
        assert_ident(d_nse_entries[1], "I");
        assert_ident(d_nse_entries[2], "J");
        let g_nse_entries = g_nse.direct_content();
        assert_eq!(g_nse_entries.len(), 2);
        assert_ident(g_nse_entries[0], "E");
        assert_ident(g_nse_entries[1], "H");
        let mut g_kids = g_nse.nested_content();
        assert!(g_kids.next().is_none());
        let mut d_kids = d_nse.nested_content();
        let (k_id, k_nse) = d_kids.next().unwrap();
        assert_eq!(k_id.to_string(), "K");
        let k_nse_entries = k_nse.direct_content();
        assert_eq!(k_nse_entries.len(), 2);
        assert_ident(k_nse_entries[0], "L");
        assert_ident(k_nse_entries[1], "M");
    }

    fn assert_ident(api: &Api, expected: &str) {
        if let Api::CxxType(cxx_type) = api {
            assert_eq!(cxx_type.ident.cxx.ident.to_string(), expected);
        } else {
            unreachable!()
        }
    }

    fn make_api(ns: Option<&str>, ident: &str) -> Api {
        let ns = match ns {
            Some(st) => Namespace::from_str(st),
            None => Namespace::none(),
        };
        let ident = Pair::new(ns, Ident::new(ident, Span::call_site()));
        Api::CxxType(ExternType {
            doc: Doc::new(),
            type_token: Token![type](Span::call_site()),
            ident,
            semi_token: Token![;](Span::call_site()),
            trusted: true,
        })
    }
}
<commit_msg>Touch up sort_by_inner_namespace implementation<commit_after>use crate::syntax::Api;
use proc_macro2::Ident;
use std::collections::BTreeMap;
use std::iter::FromIterator;

pub struct NamespaceEntries<'a> {
    direct: Vec<&'a Api>,
    nested: BTreeMap<&'a Ident, NamespaceEntries<'a>>,
}

impl<'a> NamespaceEntries<'a> {
    pub fn new(apis: &'a [Api]) -> Self {
        let api_refs = Vec::from_iter(apis);
        Self::sort_by_inner_namespace(api_refs, 0)
    }

    pub fn direct_content(&self) -> &[&'a Api] {
        &self.direct
    }

    pub fn nested_content(&self) -> impl Iterator<Item = (&Ident, &NamespaceEntries)> {
        self.nested.iter().map(|(k, entries)| (*k, entries))
    }

    fn sort_by_inner_namespace(apis: Vec<&'a Api>, depth: usize) -> Self {
        let mut direct = Vec::new();
        let mut nested_namespaces = BTreeMap::new();
        for api in apis {
            if let Some(ns) = api.namespace() {
                let first_ns_elem = ns.iter().nth(depth);
                if let Some(first_ns_elem) = first_ns_elem {
                    nested_namespaces
                        .entry(first_ns_elem)
                        .or_insert_with(Vec::new)
                        .push(api);
                    continue;
                }
            }
            direct.push(api);
        }

        let nested = nested_namespaces
            .into_iter()
            .map(|(k, apis)| (k, Self::sort_by_inner_namespace(apis, depth + 1)))
            .collect();

        NamespaceEntries { direct, nested }
    }
}

#[cfg(test)]
mod tests {
    use super::NamespaceEntries;
    use crate::syntax::namespace::Namespace;
    use crate::syntax::{Api, Doc, ExternType, Pair};
    use proc_macro2::{Ident, Span};
    use syn::Token;

    #[test]
    fn test_ns_entries_sort() {
        let entries = vec![
            make_api(None, "C"),
            make_api(None, "A"),
            make_api(Some("G"), "E"),
            make_api(Some("D"), "F"),
            make_api(Some("G"), "H"),
            make_api(Some("D::K"), "L"),
            make_api(Some("D::K"), "M"),
            make_api(None, "B"),
            make_api(Some("D"), "I"),
            make_api(Some("D"), "J"),
        ];
        let ns = NamespaceEntries::new(&entries);
        let root_entries = ns.direct_content();
        assert_eq!(root_entries.len(), 3);
        assert_ident(root_entries[0], "C");
        assert_ident(root_entries[1], "A");
        assert_ident(root_entries[2], "B");
        let mut kids = ns.nested_content();
        let (d_id, d_nse) = kids.next().unwrap();
        assert_eq!(d_id.to_string(), "D");
        let (g_id, g_nse) = kids.next().unwrap();
        assert_eq!(g_id.to_string(), "G");
        assert!(kids.next().is_none());
        let d_nse_entries = d_nse.direct_content();
        assert_eq!(d_nse_entries.len(), 3);
        assert_ident(d_nse_entries[0], "F");
        assert_ident(d_nse_entries[1], "I");
        assert_ident(d_nse_entries[2], "J");
        let g_nse_entries = g_nse.direct_content();
        assert_eq!(g_nse_entries.len(), 2);
        assert_ident(g_nse_entries[0], "E");
        assert_ident(g_nse_entries[1], "H");
        let mut g_kids = g_nse.nested_content();
        assert!(g_kids.next().is_none());
        let mut d_kids = d_nse.nested_content();
        let (k_id, k_nse) = d_kids.next().unwrap();
        assert_eq!(k_id.to_string(), "K");
        let k_nse_entries = k_nse.direct_content();
        assert_eq!(k_nse_entries.len(), 2);
        assert_ident(k_nse_entries[0], "L");
        assert_ident(k_nse_entries[1], "M");
    }

    fn assert_ident(api: &Api, expected: &str) {
        if let Api::CxxType(cxx_type) = api {
            assert_eq!(cxx_type.ident.cxx.ident.to_string(), expected);
        } else {
            unreachable!()
        }
    }

    fn make_api(ns: Option<&str>, ident: &str) -> Api {
        let ns = match ns {
            Some(st) => Namespace::from_str(st),
            None => Namespace::none(),
        };
        let ident = Pair::new(ns, Ident::new(ident, Span::call_site()));
        Api::CxxType(ExternType {
            doc: Doc::new(),
            type_token: Token![type](Span::call_site()),
            ident,
            semi_token: Token![;](Span::call_site()),
            trusted: true,
        })
    }
}
<|endoftext|>


<commit_before>// NOTE: This is a copy and adaptation of the original mod "size" from
// the crate "termion".
//
// The original "termion::terminal_size()" function only checks the size
// against the STDOUT, but to interact with the user we use a custom
// tty (/dev/tty to be precise), so we need to use a different file
// descriptor. I don't know if this "feature" will be available in
// "termion" any time soon, so fo the moment I adapt the original code
// to my needs.
use std::io;
use libc::{c_ushort, c_int};

#[cfg(target_os = "linux")]
pub const TIOCGWINSZ: usize = 0x00005413;

#[cfg(not(target_os = "linux"))]
pub const TIOCGWINSZ: usize = 0x40087468;

#[repr(C)]
struct TermSize {
    row: c_ushort,
    col: c_ushort,
    _x: c_ushort,
    _y: c_ushort,
}

#[cfg(target_pointer_width = "64")]
fn tiocgwinsz() -> u64 {
    TIOCGWINSZ as u64
}

#[cfg(target_pointer_width = "32")]
fn tiocgwinsz() -> u32 {
    TIOCGWINSZ as u32
}

// Get the size of the terminal.
pub fn terminal_size(fileno: c_int) -> io::Result<(u16, u16)> {
    use libc::ioctl;
    use std::mem;

    unsafe {
        let mut size: TermSize = mem::zeroed();

        if ioctl(fileno, tiocgwinsz().into(), &mut size as *mut _) == 0 {
            Ok((size.col as u16, size.row as u16))
        } else {
            Err(io::Error::new(
                io::ErrorKind::Other,
                "Unable to get the terminal size.",
            ))
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_size() {
        use libc::STDOUT_FILENO;

        assert!(terminal_size(STDOUT_FILENO).is_ok());
    }
}
<commit_msg>Fix musl compilation, take 2<commit_after>// NOTE: This is a copy and adaptation of the original mod "size" from
// the crate "termion".
//
// The original "termion::terminal_size()" function only checks the size
// against the STDOUT, but to interact with the user we use a custom
// tty (/dev/tty to be precise), so we need to use a different file
// descriptor. I don't know if this "feature" will be available in
// "termion" any time soon, so fo the moment I adapt the original code
// to my needs.
use std::io;
use libc::{c_ushort, c_int};

#[cfg(target_os = "linux")]
pub const TIOCGWINSZ: usize = 0x00005413;

#[cfg(not(target_os = "linux"))]
pub const TIOCGWINSZ: usize = 0x40087468;

#[repr(C)]
struct TermSize {
    row: c_ushort,
    col: c_ushort,
    _x: c_ushort,
    _y: c_ushort,
}

#[cfg(all(target_env = "musl", target_pointer_width = "64"))]
fn tiocgwinsz() -> i64 {
    TIOCGWINSZ as i64
}

#[cfg(all(target_env = "musl", target_pointer_width = "32"))]
fn tiocgwinsz() -> i32 {
    TIOCGWINSZ as i32
}

#[cfg(all(not(target_env = "musl"), target_pointer_width = "64"))]
fn tiocgwinsz() -> u64 {
    TIOCGWINSZ as u64
}

#[cfg(all(not(target_env = "musl"), target_pointer_width = "32"))]
fn tiocgwinsz() -> u32 {
    TIOCGWINSZ as u32
}

// Get the size of the terminal.
pub fn terminal_size(fileno: c_int) -> io::Result<(u16, u16)> {
    use libc::ioctl;
    use std::mem;

    unsafe {
        let mut size: TermSize = mem::zeroed();

        if ioctl(fileno, tiocgwinsz(), &mut size as *mut _) == 0 {
            Ok((size.col as u16, size.row as u16))
        } else {
            Err(io::Error::new(
                io::ErrorKind::Other,
                "Unable to get the terminal size.",
            ))
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_size() {
        use libc::STDOUT_FILENO;

        assert!(terminal_size(STDOUT_FILENO).is_ok());
    }
}
<|endoftext|>


<commit_before>use async_trait::async_trait;

#[cfg(any(feature = "tokio02", feature = "tokio1", feature = "async-std1"))]
use super::Tls;
use super::{
    client::AsyncSmtpConnection, ClientId, Credentials, Error, Mechanism, Response, SmtpInfo,
};
#[cfg(feature = "async-std1")]
use crate::AsyncStd1Transport;
use crate::Envelope;
#[cfg(feature = "tokio02")]
use crate::Tokio02Transport;
#[cfg(feature = "tokio1")]
use crate::Tokio1Transport;

#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct AsyncSmtpTransport<C> {
    // TODO: pool
    inner: AsyncSmtpClient<C>,
}

#[cfg(feature = "tokio02")]
#[async_trait]
impl Tokio02Transport for AsyncSmtpTransport<Tokio02Connector> {
    type Ok = Response;
    type Error = Error;

    /// Sends an email
    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        let mut conn = self.inner.connection().await?;

        let result = conn.send(envelope, email).await?;

        conn.quit().await?;

        Ok(result)
    }
}

#[cfg(feature = "tokio1")]
#[async_trait]
impl Tokio1Transport for AsyncSmtpTransport<Tokio1Connector> {
    type Ok = Response;
    type Error = Error;

    /// Sends an email
    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        let mut conn = self.inner.connection().await?;

        let result = conn.send(envelope, email).await?;

        conn.quit().await?;

        Ok(result)
    }
}

#[cfg(feature = "async-std1")]
#[async_trait]
impl AsyncStd1Transport for AsyncSmtpTransport<AsyncStd1Connector> {
    type Ok = Response;
    type Error = Error;

    /// Sends an email
    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        let mut conn = self.inner.connection().await?;

        let result = conn.send(envelope, email).await?;

        conn.quit().await?;

        Ok(result)
    }
}

impl<C> AsyncSmtpTransport<C>
where
    C: AsyncSmtpConnector,
{
    /// Simple and secure transport, using TLS connections to communicate with the SMTP server
    ///
    /// The right option for most SMTP servers.
    ///
    /// Creates an encrypted transport over submissions port, using the provided domain
    /// to validate TLS certificates.
    #[cfg(any(
        feature = "tokio02-native-tls",
        feature = "tokio02-rustls-tls",
        feature = "tokio1-native-tls",
        feature = "tokio1-rustls-tls",
        feature = "async-std1-native-tls",
        feature = "async-std1-rustls-tls"
    ))]
    pub fn relay(relay: &str) -> Result<AsyncSmtpTransportBuilder, Error> {
        use super::{TlsParameters, SUBMISSIONS_PORT};

        let tls_parameters = TlsParameters::new(relay.into())?;

        Ok(Self::builder_dangerous(relay)
            .port(SUBMISSIONS_PORT)
            .tls(Tls::Wrapper(tls_parameters)))
    }

    /// Simple an secure transport, using STARTTLS to obtain encrypted connections
    ///
    /// Alternative to [`AsyncSmtpTransport::relay`](#method.relay), for SMTP servers
    /// that don't take SMTPS connections.
    ///
    /// Creates an encrypted transport over submissions port, by first connecting using
    /// an unencrypted connection and then upgrading it with STARTTLS. The provided
    /// domain is used to validate TLS certificates.
    ///
    /// An error is returned if the connection can't be upgraded. No credentials
    /// or emails will be sent to the server, protecting from downgrade attacks.
    #[cfg(any(
        feature = "tokio02-native-tls",
        feature = "tokio02-rustls-tls",
        feature = "tokio1-native-tls",
        feature = "tokio1-rustls-tls",
        feature = "async-std1-native-tls",
        feature = "async-std1-rustls-tls"
    ))]
    pub fn starttls_relay(relay: &str) -> Result<AsyncSmtpTransportBuilder, Error> {
        use super::{TlsParameters, SUBMISSION_PORT};

        let tls_parameters = TlsParameters::new(relay.into())?;

        Ok(Self::builder_dangerous(relay)
            .port(SUBMISSION_PORT)
            .tls(Tls::Required(tls_parameters)))
    }

    /// Creates a new local SMTP client to port 25
    ///
    /// Shortcut for local unencrypted relay (typical local email daemon that will handle relaying)
    pub fn unencrypted_localhost() -> AsyncSmtpTransport<C> {
        Self::builder_dangerous("localhost").build()
    }

    /// Creates a new SMTP client
    ///
    /// Defaults are:
    ///
    /// * No authentication
    /// * No TLS
    /// * Port 25
    ///
    /// Consider using [`AsyncSmtpTransport::relay`](#method.relay) or
    /// [`AsyncSmtpTransport::starttls_relay`](#method.starttls_relay) instead,
    /// if possible.
    pub fn builder_dangerous<T: Into<String>>(server: T) -> AsyncSmtpTransportBuilder {
        let new = SmtpInfo {
            server: server.into(),
            ..Default::default()
        };
        AsyncSmtpTransportBuilder { info: new }
    }
}

/// Contains client configuration.
/// Instances of this struct can be created using functions of [`AsyncSmtpTransport`].
#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct AsyncSmtpTransportBuilder {
    info: SmtpInfo,
}

/// Builder for the SMTP `AsyncSmtpTransport`
impl AsyncSmtpTransportBuilder {
    /// Set the name used during EHLO
    pub fn hello_name(mut self, name: ClientId) -> Self {
        self.info.hello_name = name;
        self
    }

    /// Set the authentication mechanism to use
    pub fn credentials(mut self, credentials: Credentials) -> Self {
        self.info.credentials = Some(credentials);
        self
    }

    /// Set the authentication mechanism to use
    pub fn authentication(mut self, mechanisms: Vec<Mechanism>) -> Self {
        self.info.authentication = mechanisms;
        self
    }

    /// Set the port to use
    pub fn port(mut self, port: u16) -> Self {
        self.info.port = port;
        self
    }

    /// Set the TLS settings to use
    #[cfg(any(
        feature = "tokio02-native-tls",
        feature = "tokio02-rustls-tls",
        feature = "tokio1-native-tls",
        feature = "tokio1-rustls-tls",
        feature = "async-std1-native-tls",
        feature = "async-std1-rustls-tls"
    ))]
    pub fn tls(mut self, tls: Tls) -> Self {
        self.info.tls = tls;
        self
    }

    /// Build the transport (with default pool if enabled)
    pub fn build<C>(self) -> AsyncSmtpTransport<C>
    where
        C: AsyncSmtpConnector,
    {
        let connector = Default::default();
        let client = AsyncSmtpClient {
            connector,
            info: self.info,
        };
        AsyncSmtpTransport { inner: client }
    }
}

/// Build client
#[derive(Clone)]
pub struct AsyncSmtpClient<C> {
    connector: C,
    info: SmtpInfo,
}

impl<C> AsyncSmtpClient<C>
where
    C: AsyncSmtpConnector,
{
    /// Creates a new connection directly usable to send emails
    ///
    /// Handles encryption and authentication
    pub async fn connection(&self) -> Result<AsyncSmtpConnection, Error> {
        let mut conn = C::connect(
            &self.info.server,
            self.info.port,
            &self.info.hello_name,
            &self.info.tls,
        )
        .await?;

        if let Some(credentials) = &self.info.credentials {
            conn.auth(&self.info.authentication, &credentials).await?;
        }
        Ok(conn)
    }
}

#[async_trait]
pub trait AsyncSmtpConnector: Default + private::Sealed {
    async fn connect(
        hostname: &str,
        port: u16,
        hello_name: &ClientId,
        tls: &Tls,
    ) -> Result<AsyncSmtpConnection, Error>;
}

#[derive(Debug, Copy, Clone, Default)]
#[cfg(feature = "tokio02")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio02")))]
pub struct Tokio02Connector;

#[async_trait]
#[cfg(feature = "tokio02")]
impl AsyncSmtpConnector for Tokio02Connector {
    async fn connect(
        hostname: &str,
        port: u16,
        hello_name: &ClientId,
        tls: &Tls,
    ) -> Result<AsyncSmtpConnection, Error> {
        #[allow(clippy::match_single_binding)]
        let tls_parameters = match tls {
            #[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
            Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()),
            _ => None,
        };
        #[allow(unused_mut)]
        let mut conn =
            AsyncSmtpConnection::connect_tokio02(hostname, port, hello_name, tls_parameters)
                .await?;

        #[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
        match tls {
            Tls::Opportunistic(ref tls_parameters) => {
                if conn.can_starttls() {
                    conn.starttls(tls_parameters.clone(), hello_name).await?;
                }
            }
            Tls::Required(ref tls_parameters) => {
                conn.starttls(tls_parameters.clone(), hello_name).await?;
            }
            _ => (),
        }

        Ok(conn)
    }
}

#[derive(Debug, Copy, Clone, Default)]
#[cfg(feature = "tokio1")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio1")))]
pub struct Tokio1Connector;

#[async_trait]
#[cfg(feature = "tokio1")]
impl AsyncSmtpConnector for Tokio1Connector {
    async fn connect(
        hostname: &str,
        port: u16,
        hello_name: &ClientId,
        tls: &Tls,
    ) -> Result<AsyncSmtpConnection, Error> {
        #[allow(clippy::match_single_binding)]
        let tls_parameters = match tls {
            #[cfg(any(feature = "tokio1-native-tls", feature = "tokio1-rustls-tls"))]
            Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()),
            _ => None,
        };
        #[allow(unused_mut)]
        let mut conn =
            AsyncSmtpConnection::connect_tokio1(hostname, port, hello_name, tls_parameters).await?;

        #[cfg(any(feature = "tokio1-native-tls", feature = "tokio1-rustls-tls"))]
        match tls {
            Tls::Opportunistic(ref tls_parameters) => {
                if conn.can_starttls() {
                    conn.starttls(tls_parameters.clone(), hello_name).await?;
                }
            }
            Tls::Required(ref tls_parameters) => {
                conn.starttls(tls_parameters.clone(), hello_name).await?;
            }
            _ => (),
        }

        Ok(conn)
    }
}

#[derive(Debug, Copy, Clone, Default)]
#[cfg(feature = "async-std1")]
#[cfg_attr(docsrs, doc(cfg(feature = "async-std1")))]
pub struct AsyncStd1Connector;

#[async_trait]
#[cfg(feature = "async-std1")]
impl AsyncSmtpConnector for AsyncStd1Connector {
    async fn connect(
        hostname: &str,
        port: u16,
        hello_name: &ClientId,
        tls: &Tls,
    ) -> Result<AsyncSmtpConnection, Error> {
        #[allow(clippy::match_single_binding)]
        let tls_parameters = match tls {
            #[cfg(any(feature = "async-std1-native-tls", feature = "async-std1-rustls-tls"))]
            Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()),
            _ => None,
        };
        #[allow(unused_mut)]
        let mut conn =
            AsyncSmtpConnection::connect_asyncstd1(hostname, port, hello_name, tls_parameters)
                .await?;

        #[cfg(any(feature = "async-std1-native-tls", feature = "async-std1-rustls-tls"))]
        match tls {
            Tls::Opportunistic(ref tls_parameters) => {
                if conn.can_starttls() {
                    conn.starttls(tls_parameters.clone(), hello_name).await?;
                }
            }
            Tls::Required(ref tls_parameters) => {
                conn.starttls(tls_parameters.clone(), hello_name).await?;
            }
            _ => (),
        }

        Ok(conn)
    }
}

mod private {
    use super::*;

    pub trait Sealed {}

    #[cfg(feature = "tokio02")]
    impl Sealed for Tokio02Connector {}

    #[cfg(feature = "tokio1")]
    impl Sealed for Tokio1Connector {}

    #[cfg(feature = "async-std1")]
    impl Sealed for AsyncStd1Connector {}
}
<commit_msg>Better seal AsyncSmtpConnector (#534)<commit_after>use std::marker::PhantomData;

use async_trait::async_trait;

#[cfg(any(feature = "tokio02", feature = "tokio1", feature = "async-std1"))]
use super::Tls;
use super::{
    client::AsyncSmtpConnection, ClientId, Credentials, Error, Mechanism, Response, SmtpInfo,
};
#[cfg(feature = "async-std1")]
use crate::AsyncStd1Transport;
use crate::Envelope;
#[cfg(feature = "tokio02")]
use crate::Tokio02Transport;
#[cfg(feature = "tokio1")]
use crate::Tokio1Transport;

#[allow(missing_debug_implementations)]
pub struct AsyncSmtpTransport<C> {
    // TODO: pool
    inner: AsyncSmtpClient<C>,
}

#[cfg(feature = "tokio02")]
#[async_trait]
impl Tokio02Transport for AsyncSmtpTransport<Tokio02Connector> {
    type Ok = Response;
    type Error = Error;

    /// Sends an email
    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        let mut conn = self.inner.connection().await?;

        let result = conn.send(envelope, email).await?;

        conn.quit().await?;

        Ok(result)
    }
}

#[cfg(feature = "tokio1")]
#[async_trait]
impl Tokio1Transport for AsyncSmtpTransport<Tokio1Connector> {
    type Ok = Response;
    type Error = Error;

    /// Sends an email
    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        let mut conn = self.inner.connection().await?;

        let result = conn.send(envelope, email).await?;

        conn.quit().await?;

        Ok(result)
    }
}

#[cfg(feature = "async-std1")]
#[async_trait]
impl AsyncStd1Transport for AsyncSmtpTransport<AsyncStd1Connector> {
    type Ok = Response;
    type Error = Error;

    /// Sends an email
    async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error> {
        let mut conn = self.inner.connection().await?;

        let result = conn.send(envelope, email).await?;

        conn.quit().await?;

        Ok(result)
    }
}

impl<C> AsyncSmtpTransport<C>
where
    C: AsyncSmtpConnector,
{
    /// Simple and secure transport, using TLS connections to communicate with the SMTP server
    ///
    /// The right option for most SMTP servers.
    ///
    /// Creates an encrypted transport over submissions port, using the provided domain
    /// to validate TLS certificates.
    #[cfg(any(
        feature = "tokio02-native-tls",
        feature = "tokio02-rustls-tls",
        feature = "tokio1-native-tls",
        feature = "tokio1-rustls-tls",
        feature = "async-std1-native-tls",
        feature = "async-std1-rustls-tls"
    ))]
    pub fn relay(relay: &str) -> Result<AsyncSmtpTransportBuilder, Error> {
        use super::{TlsParameters, SUBMISSIONS_PORT};

        let tls_parameters = TlsParameters::new(relay.into())?;

        Ok(Self::builder_dangerous(relay)
            .port(SUBMISSIONS_PORT)
            .tls(Tls::Wrapper(tls_parameters)))
    }

    /// Simple an secure transport, using STARTTLS to obtain encrypted connections
    ///
    /// Alternative to [`AsyncSmtpTransport::relay`](#method.relay), for SMTP servers
    /// that don't take SMTPS connections.
    ///
    /// Creates an encrypted transport over submissions port, by first connecting using
    /// an unencrypted connection and then upgrading it with STARTTLS. The provided
    /// domain is used to validate TLS certificates.
    ///
    /// An error is returned if the connection can't be upgraded. No credentials
    /// or emails will be sent to the server, protecting from downgrade attacks.
    #[cfg(any(
        feature = "tokio02-native-tls",
        feature = "tokio02-rustls-tls",
        feature = "tokio1-native-tls",
        feature = "tokio1-rustls-tls",
        feature = "async-std1-native-tls",
        feature = "async-std1-rustls-tls"
    ))]
    pub fn starttls_relay(relay: &str) -> Result<AsyncSmtpTransportBuilder, Error> {
        use super::{TlsParameters, SUBMISSION_PORT};

        let tls_parameters = TlsParameters::new(relay.into())?;

        Ok(Self::builder_dangerous(relay)
            .port(SUBMISSION_PORT)
            .tls(Tls::Required(tls_parameters)))
    }

    /// Creates a new local SMTP client to port 25
    ///
    /// Shortcut for local unencrypted relay (typical local email daemon that will handle relaying)
    pub fn unencrypted_localhost() -> AsyncSmtpTransport<C> {
        Self::builder_dangerous("localhost").build()
    }

    /// Creates a new SMTP client
    ///
    /// Defaults are:
    ///
    /// * No authentication
    /// * No TLS
    /// * Port 25
    ///
    /// Consider using [`AsyncSmtpTransport::relay`](#method.relay) or
    /// [`AsyncSmtpTransport::starttls_relay`](#method.starttls_relay) instead,
    /// if possible.
    pub fn builder_dangerous<T: Into<String>>(server: T) -> AsyncSmtpTransportBuilder {
        let new = SmtpInfo {
            server: server.into(),
            ..Default::default()
        };
        AsyncSmtpTransportBuilder { info: new }
    }
}

impl<C> Clone for AsyncSmtpTransport<C>
where
    C: AsyncSmtpConnector,
{
    fn clone(&self) -> Self {
        Self {
            inner: self.inner.clone(),
        }
    }
}

/// Contains client configuration.
/// Instances of this struct can be created using functions of [`AsyncSmtpTransport`].
#[allow(missing_debug_implementations)]
#[derive(Clone)]
pub struct AsyncSmtpTransportBuilder {
    info: SmtpInfo,
}

/// Builder for the SMTP `AsyncSmtpTransport`
impl AsyncSmtpTransportBuilder {
    /// Set the name used during EHLO
    pub fn hello_name(mut self, name: ClientId) -> Self {
        self.info.hello_name = name;
        self
    }

    /// Set the authentication mechanism to use
    pub fn credentials(mut self, credentials: Credentials) -> Self {
        self.info.credentials = Some(credentials);
        self
    }

    /// Set the authentication mechanism to use
    pub fn authentication(mut self, mechanisms: Vec<Mechanism>) -> Self {
        self.info.authentication = mechanisms;
        self
    }

    /// Set the port to use
    pub fn port(mut self, port: u16) -> Self {
        self.info.port = port;
        self
    }

    /// Set the TLS settings to use
    #[cfg(any(
        feature = "tokio02-native-tls",
        feature = "tokio02-rustls-tls",
        feature = "tokio1-native-tls",
        feature = "tokio1-rustls-tls",
        feature = "async-std1-native-tls",
        feature = "async-std1-rustls-tls"
    ))]
    pub fn tls(mut self, tls: Tls) -> Self {
        self.info.tls = tls;
        self
    }

    /// Build the transport (with default pool if enabled)
    pub fn build<C>(self) -> AsyncSmtpTransport<C>
    where
        C: AsyncSmtpConnector,
    {
        let client = AsyncSmtpClient {
            info: self.info,
            marker_: PhantomData,
        };
        AsyncSmtpTransport { inner: client }
    }
}

/// Build client
pub struct AsyncSmtpClient<C> {
    info: SmtpInfo,
    marker_: PhantomData<C>,
}

impl<C> AsyncSmtpClient<C>
where
    C: AsyncSmtpConnector,
{
    /// Creates a new connection directly usable to send emails
    ///
    /// Handles encryption and authentication
    pub async fn connection(&self) -> Result<AsyncSmtpConnection, Error> {
        let mut conn = C::connect(
            &self.info.server,
            self.info.port,
            &self.info.hello_name,
            &self.info.tls,
        )
        .await?;

        if let Some(credentials) = &self.info.credentials {
            conn.auth(&self.info.authentication, &credentials).await?;
        }
        Ok(conn)
    }
}

impl<C> AsyncSmtpClient<C>
where
    C: AsyncSmtpConnector,
{
    fn clone(&self) -> Self {
        Self {
            info: self.info.clone(),
            marker_: PhantomData,
        }
    }
}

#[async_trait]
pub trait AsyncSmtpConnector: private::Sealed {
    #[doc(hidden)]
    async fn connect(
        hostname: &str,
        port: u16,
        hello_name: &ClientId,
        tls: &Tls,
    ) -> Result<AsyncSmtpConnection, Error>;
}

#[allow(missing_copy_implementations)]
#[non_exhaustive]
#[cfg(feature = "tokio02")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio02")))]
pub struct Tokio02Connector;

#[async_trait]
#[cfg(feature = "tokio02")]
impl AsyncSmtpConnector for Tokio02Connector {
    #[doc(hidden)]
    async fn connect(
        hostname: &str,
        port: u16,
        hello_name: &ClientId,
        tls: &Tls,
    ) -> Result<AsyncSmtpConnection, Error> {
        #[allow(clippy::match_single_binding)]
        let tls_parameters = match tls {
            #[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
            Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()),
            _ => None,
        };
        #[allow(unused_mut)]
        let mut conn =
            AsyncSmtpConnection::connect_tokio02(hostname, port, hello_name, tls_parameters)
                .await?;

        #[cfg(any(feature = "tokio02-native-tls", feature = "tokio02-rustls-tls"))]
        match tls {
            Tls::Opportunistic(ref tls_parameters) => {
                if conn.can_starttls() {
                    conn.starttls(tls_parameters.clone(), hello_name).await?;
                }
            }
            Tls::Required(ref tls_parameters) => {
                conn.starttls(tls_parameters.clone(), hello_name).await?;
            }
            _ => (),
        }

        Ok(conn)
    }
}

#[allow(missing_copy_implementations)]
#[non_exhaustive]
#[cfg(feature = "tokio1")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio1")))]
pub struct Tokio1Connector;

#[async_trait]
#[cfg(feature = "tokio1")]
impl AsyncSmtpConnector for Tokio1Connector {
    #[doc(hidden)]
    async fn connect(
        hostname: &str,
        port: u16,
        hello_name: &ClientId,
        tls: &Tls,
    ) -> Result<AsyncSmtpConnection, Error> {
        #[allow(clippy::match_single_binding)]
        let tls_parameters = match tls {
            #[cfg(any(feature = "tokio1-native-tls", feature = "tokio1-rustls-tls"))]
            Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()),
            _ => None,
        };
        #[allow(unused_mut)]
        let mut conn =
            AsyncSmtpConnection::connect_tokio1(hostname, port, hello_name, tls_parameters).await?;

        #[cfg(any(feature = "tokio1-native-tls", feature = "tokio1-rustls-tls"))]
        match tls {
            Tls::Opportunistic(ref tls_parameters) => {
                if conn.can_starttls() {
                    conn.starttls(tls_parameters.clone(), hello_name).await?;
                }
            }
            Tls::Required(ref tls_parameters) => {
                conn.starttls(tls_parameters.clone(), hello_name).await?;
            }
            _ => (),
        }

        Ok(conn)
    }
}

#[allow(missing_copy_implementations)]
#[non_exhaustive]
#[cfg(feature = "async-std1")]
#[cfg_attr(docsrs, doc(cfg(feature = "async-std1")))]
pub struct AsyncStd1Connector;

#[async_trait]
#[cfg(feature = "async-std1")]
impl AsyncSmtpConnector for AsyncStd1Connector {
    #[doc(hidden)]
    async fn connect(
        hostname: &str,
        port: u16,
        hello_name: &ClientId,
        tls: &Tls,
    ) -> Result<AsyncSmtpConnection, Error> {
        #[allow(clippy::match_single_binding)]
        let tls_parameters = match tls {
            #[cfg(any(feature = "async-std1-native-tls", feature = "async-std1-rustls-tls"))]
            Tls::Wrapper(ref tls_parameters) => Some(tls_parameters.clone()),
            _ => None,
        };
        #[allow(unused_mut)]
        let mut conn =
            AsyncSmtpConnection::connect_asyncstd1(hostname, port, hello_name, tls_parameters)
                .await?;

        #[cfg(any(feature = "async-std1-native-tls", feature = "async-std1-rustls-tls"))]
        match tls {
            Tls::Opportunistic(ref tls_parameters) => {
                if conn.can_starttls() {
                    conn.starttls(tls_parameters.clone(), hello_name).await?;
                }
            }
            Tls::Required(ref tls_parameters) => {
                conn.starttls(tls_parameters.clone(), hello_name).await?;
            }
            _ => (),
        }

        Ok(conn)
    }
}

mod private {
    use super::*;

    pub trait Sealed {}

    #[cfg(feature = "tokio02")]
    impl Sealed for Tokio02Connector {}

    #[cfg(feature = "tokio1")]
    impl Sealed for Tokio1Connector {}

    #[cfg(feature = "async-std1")]
    impl Sealed for AsyncStd1Connector {}
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(rocket_macros)]

extern crate rocket;
use rocket::Rocket;

#[route(GET, path = "/users/<name>")]
fn user(name: &str, other: i8) -> Option<&'static str> {
    if name == "Sergio" {
        Some("Hello, Sergio!")
    } else {
        None
    }
}

fn main() {
    Rocket::new("localhost", 8000).mount_and_launch("/", routes![user]);
}
<commit_msg>Accidentally broke optional_result example. Now fixed.<commit_after>#![feature(plugin)]
#![plugin(rocket_macros)]

extern crate rocket;
use rocket::Rocket;

#[route(GET, path = "/users/<name>")]
fn user(name: &str) -> Option<&'static str> {
    if name == "Sergio" {
        Some("Hello, Sergio!")
    } else {
        None
    }
}

fn main() {
    Rocket::new("localhost", 8000).mount_and_launch("/", routes![user]);
}
<|endoftext|>


<commit_before>use bson::{self, Bson};
use mongodb::{Client, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use mongodb::db::options::CreateUserOptions;
use mongodb::db::roles::{AllDatabaseRole, SingleDatabaseRole, Role};

#[test]
fn create_collection() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("create_collection");
    db.drop_database().unwrap();

    // Build collections
    db.create_collection("test1", None).unwrap();
    db.create_collection("test2", None).unwrap();

    // Check for namespaces
    let mut cursor = db.list_collections_with_batch_size(None, 1)
        .expect("Failed to execute list_collections command.");

    let results = cursor.next_n(5).unwrap();

    let v3_0 = cfg!(feature = "mongodb_3_0");
    let result_size = if v3_0 { 3 } else { 2 };
    assert_eq!(result_size, results.len());

    if v3_0 {
        match results[0].get("name") {
            Some(&Bson::String(ref name)) => assert_eq!("system.indexes", name),
            _ => panic!("Expected BSON string!"),
        }
    }

    match results[result_size - 2].get("name") {
        Some(&Bson::String(ref name)) => assert_eq!("test1", name),
        _ => panic!("Expected BSON string!"),
    }
    match results[result_size - 1].get("name") {
        Some(&Bson::String(ref name)) => assert_eq!("test2", name),
        _ => panic!("Expected BSON string!"),
    }
}

#[test]
fn list_collections() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("list_collections");

    db.drop_database().expect("Failed to drop database");

    // Build collections
    db.collection("test")
        .insert_one(bson::Document::new(), None)
        .expect("Failed to insert placeholder document into collection");
    db.collection("test2")
        .insert_one(bson::Document::new(), None)
        .expect("Failed to insert placeholder document into collection");

    // Check for namespaces
    let mut cursor = db.list_collections_with_batch_size(None, 1)
        .expect("Failed to execute list_collections command.");

    let results = cursor.next_n(5).unwrap();

    let v3_0 = cfg!(feature = "mongodb_3_0");
    let result_size = if v3_0 { 3 } else { 2 };
    assert_eq!(result_size, results.len());

    if v3_0 {
        match results[0].get("name") {
            Some(&Bson::String(ref name)) => assert_eq!("system.indexes", name),
            _ => panic!("Expected BSON string!"),
        };
    }

    match results[result_size - 2].get("name") {
        Some(&Bson::String(ref name)) => assert_eq!("test", name),
        _ => panic!("Expected BSON string!"),
    };

    match results[result_size - 1].get("name") {
        Some(&Bson::String(ref name)) => assert_eq!("test2", name),
        _ => panic!("Expected BSON string!"),
    }
}

#[test]
fn create_and_get_users() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("create_and_get_users");
    db.drop_database().unwrap();
    db.drop_all_users(None).unwrap();

    let saghm_options = CreateUserOptions {
        custom_data: Some(doc! { "foo" => "bar" }),
        roles: vec![Role::Single {
                        role: SingleDatabaseRole::DbAdmin,
                        db: String::from("test"),
                    },
                    Role::All(AllDatabaseRole::ReadWrite)],
        write_concern: None,
    };

    db.create_user("saghm", "ilikepuns!", Some(saghm_options)).unwrap();

    let kevin_options = CreateUserOptions {
        custom_data: None,
        roles: vec![Role::All(AllDatabaseRole::Read)],
        write_concern: None,
    };

    db.create_user("kevin",
                     "ihavenosenseofhumorandthereforeihatepuns!",
                     Some(kevin_options))
        .unwrap();
    db.create_user("val", "ilikeangularjs!", None).unwrap();

    let user = db.get_user("saghm", None).unwrap();

    match user.get("db") {
        Some(&Bson::String(ref s)) => assert_eq!("create_and_get_users", s),
        _ => {
            panic!("Invalid `db` specified for user 'saghm': {:?}",
                   user.get("db"))
        }
    };

    let data = match user.get("customData") {
        Some(&Bson::Document(ref d)) => d.clone(),
        _ => panic!("Invalid `customData` specified for user 'saghm'"),
    };

    match data.get("foo") {
        Some(&Bson::String(ref s)) => assert_eq!("bar", s),
        _ => panic!("Invalid custom data for user 'saghm': {}", data),
    };

    let users = db.get_users(vec!["kevin", "val"], None).unwrap();
    assert_eq!(users.len(), 2 as usize);

    match users[0].get("user") {
        Some(&Bson::String(ref s)) => assert_eq!("kevin", s),
        _ => panic!("User isn't named 'kevin' but should be"),
    };

    match users[1].get("user") {
        Some(&Bson::String(ref s)) => assert_eq!("val", s),
        _ => panic!("User isn't named 'val' but should be"),
    };

    let users = db.get_all_users(false).unwrap();

    assert_eq!(users.len(), 3);

    match users[0].get("user") {
        Some(&Bson::String(ref s)) => assert_eq!("saghm", s),
        _ => panic!("User isn't named 'saghm' but should be"),
    };

    match users[1].get("user") {
        Some(&Bson::String(ref s)) => assert_eq!("kevin", s),
        _ => panic!("User isn't named 'kevin' but should be"),
    };

    match users[2].get("user") {
        Some(&Bson::String(ref s)) => assert_eq!("val", s),
        _ => panic!("User isn't named 'val' but should be"),
    };
}

#[test]
fn get_version() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("create_and_get_users");
    let version = db.version().unwrap();
}
<commit_msg>update test db name<commit_after>use bson::{self, Bson};
use mongodb::{Client, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use mongodb::db::options::CreateUserOptions;
use mongodb::db::roles::{AllDatabaseRole, SingleDatabaseRole, Role};

#[test]
fn create_collection() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("create_collection");
    db.drop_database().unwrap();

    // Build collections
    db.create_collection("test1", None).unwrap();
    db.create_collection("test2", None).unwrap();

    // Check for namespaces
    let mut cursor = db.list_collections_with_batch_size(None, 1)
        .expect("Failed to execute list_collections command.");

    let results = cursor.next_n(5).unwrap();

    let v3_0 = cfg!(feature = "mongodb_3_0");
    let result_size = if v3_0 { 3 } else { 2 };
    assert_eq!(result_size, results.len());

    if v3_0 {
        match results[0].get("name") {
            Some(&Bson::String(ref name)) => assert_eq!("system.indexes", name),
            _ => panic!("Expected BSON string!"),
        }
    }

    match results[result_size - 2].get("name") {
        Some(&Bson::String(ref name)) => assert_eq!("test1", name),
        _ => panic!("Expected BSON string!"),
    }
    match results[result_size - 1].get("name") {
        Some(&Bson::String(ref name)) => assert_eq!("test2", name),
        _ => panic!("Expected BSON string!"),
    }
}

#[test]
fn list_collections() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("list_collections");

    db.drop_database().expect("Failed to drop database");

    // Build collections
    db.collection("test")
        .insert_one(bson::Document::new(), None)
        .expect("Failed to insert placeholder document into collection");
    db.collection("test2")
        .insert_one(bson::Document::new(), None)
        .expect("Failed to insert placeholder document into collection");

    // Check for namespaces
    let mut cursor = db.list_collections_with_batch_size(None, 1)
        .expect("Failed to execute list_collections command.");

    let results = cursor.next_n(5).unwrap();

    let v3_0 = cfg!(feature = "mongodb_3_0");
    let result_size = if v3_0 { 3 } else { 2 };
    assert_eq!(result_size, results.len());

    if v3_0 {
        match results[0].get("name") {
            Some(&Bson::String(ref name)) => assert_eq!("system.indexes", name),
            _ => panic!("Expected BSON string!"),
        };
    }

    match results[result_size - 2].get("name") {
        Some(&Bson::String(ref name)) => assert_eq!("test", name),
        _ => panic!("Expected BSON string!"),
    };

    match results[result_size - 1].get("name") {
        Some(&Bson::String(ref name)) => assert_eq!("test2", name),
        _ => panic!("Expected BSON string!"),
    }
}

#[test]
fn create_and_get_users() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("create_and_get_users");
    db.drop_database().unwrap();
    db.drop_all_users(None).unwrap();

    let saghm_options = CreateUserOptions {
        custom_data: Some(doc! { "foo" => "bar" }),
        roles: vec![Role::Single {
                        role: SingleDatabaseRole::DbAdmin,
                        db: String::from("test"),
                    },
                    Role::All(AllDatabaseRole::ReadWrite)],
        write_concern: None,
    };

    db.create_user("saghm", "ilikepuns!", Some(saghm_options)).unwrap();

    let kevin_options = CreateUserOptions {
        custom_data: None,
        roles: vec![Role::All(AllDatabaseRole::Read)],
        write_concern: None,
    };

    db.create_user("kevin",
                     "ihavenosenseofhumorandthereforeihatepuns!",
                     Some(kevin_options))
        .unwrap();
    db.create_user("val", "ilikeangularjs!", None).unwrap();

    let user = db.get_user("saghm", None).unwrap();

    match user.get("db") {
        Some(&Bson::String(ref s)) => assert_eq!("create_and_get_users", s),
        _ => {
            panic!("Invalid `db` specified for user 'saghm': {:?}",
                   user.get("db"))
        }
    };

    let data = match user.get("customData") {
        Some(&Bson::Document(ref d)) => d.clone(),
        _ => panic!("Invalid `customData` specified for user 'saghm'"),
    };

    match data.get("foo") {
        Some(&Bson::String(ref s)) => assert_eq!("bar", s),
        _ => panic!("Invalid custom data for user 'saghm': {}", data),
    };

    let users = db.get_users(vec!["kevin", "val"], None).unwrap();
    assert_eq!(users.len(), 2 as usize);

    match users[0].get("user") {
        Some(&Bson::String(ref s)) => assert_eq!("kevin", s),
        _ => panic!("User isn't named 'kevin' but should be"),
    };

    match users[1].get("user") {
        Some(&Bson::String(ref s)) => assert_eq!("val", s),
        _ => panic!("User isn't named 'val' but should be"),
    };

    let users = db.get_all_users(false).unwrap();

    assert_eq!(users.len(), 3);

    match users[0].get("user") {
        Some(&Bson::String(ref s)) => assert_eq!("saghm", s),
        _ => panic!("User isn't named 'saghm' but should be"),
    };

    match users[1].get("user") {
        Some(&Bson::String(ref s)) => assert_eq!("kevin", s),
        _ => panic!("User isn't named 'kevin' but should be"),
    };

    match users[2].get("user") {
        Some(&Bson::String(ref s)) => assert_eq!("val", s),
        _ => panic!("User isn't named 'val' but should be"),
    };
}

#[test]
fn get_version() {
    let client = Client::connect("localhost", 27017).unwrap();
    let db = client.db("get_version");
    let version = db.version().unwrap();
}
<|endoftext|>


<commit_before>use nom::{self, IResult};
use std::str;

pub enum Expr<'a> {
     Var(&'a [u8]),
     Filter(&'a str, Box<Expr<'a>>),
}

pub enum Node<'a> {
    Lit(&'a [u8]),
    Expr(Expr<'a>),
    Cond(Vec<(Option<Expr<'a>>, Vec<Node<'a>>)>),
}

pub type Nodes<'a> = Vec<Node<'a>>;
pub type Conds<'a> = Vec<(Option<Expr<'a>>, Nodes<'a>)>;

fn take_content(i: &[u8]) -> IResult<&[u8], Node> {
    if i.len() < 1 || i[0] == b'{' {
        return IResult::Error(error_position!(nom::ErrorKind::TakeUntil, i));
    }
    for (j, c) in i.iter().enumerate() {
        if *c == b'{' {
            if i.len() < j + 2 {
                return IResult::Done(&i[..0], Node::Lit(&i[..]));
            } else if i[j + 1] == '{' as u8 {
                return IResult::Done(&i[j..], Node::Lit(&i[..j]));
            } else if i[j + 1] == '%' as u8 {
                return IResult::Done(&i[j..], Node::Lit(&i[..j]));
            }
        }
    }
    IResult::Done(&i[..0], Node::Lit(&i[..]))
}

named!(expr_var<Expr>, map!(nom::alphanumeric, Expr::Var));

fn expr_filtered(i: &[u8]) -> IResult<&[u8], Expr> {
    let (mut left, mut expr) = match expr_var(i) {
        IResult::Error(err) => { return IResult::Error(err); },
        IResult::Incomplete(needed) => { return IResult::Incomplete(needed); },
        IResult::Done(left, res) => (left, res),
    };
    while left[0] == b'|' {
        match nom::alphanumeric(&left[1..]) {
            IResult::Error(err) => {
                return IResult::Error(err);
            },
            IResult::Incomplete(needed) => {
                return IResult::Incomplete(needed);
            },
            IResult::Done(new_left, res) => {
                left = new_left;
                expr = Expr::Filter(str::from_utf8(res).unwrap(), Box::new(expr));
            },
        };
    }
    return IResult::Done(left, expr);
}

named!(expr_node<Node>, map!(
    delimited!(tag_s!("{{"), ws!(expr_filtered), tag_s!("}}")),
    Node::Expr));

named!(cond_elif<(Option<Expr>, Nodes)>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("elif")) >>
    cond: ws!(expr_filtered) >>
    tag_s!("%}") >>
    block: parse_template >>
    (Some(cond), block)));

named!(cond_else<Nodes>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("else")) >>
    tag_s!("%}") >>
    block: parse_template >>
    (block)));

named!(block_if<Node>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("if")) >>
    cond: ws!(expr_filtered) >>
    tag_s!("%}") >>
    block: parse_template >>
    elifs: many0!(cond_elif) >>
    rest: opt!(cond_else) >>
    tag_s!("{%") >>
    ws!(tag_s!("endif")) >>
    tag_s!("%}") >>
    ({
        let mut res = Vec::new();
        res.push((Some(cond), block));
        res.extend(elifs);
        if let Some(else_block) = rest {
            res.push((None, else_block));
        }
        Node::Cond(res)
    })));

named!(parse_template< Vec<Node> >, many1!(alt!(
    take_content |
    expr_node |
    block_if)));

pub fn parse<'a>(src: &'a str) -> Vec<Node> {
    match parse_template(src.as_bytes()) {
        IResult::Done(_, res) => res,
        IResult::Error(err) => panic!("problems parsing template source: {}", err),
        IResult::Incomplete(_) => panic!("parsing incomplete"),
    }
}
<commit_msg>Simplify parser by using type alias<commit_after>use nom::{self, IResult};
use std::str;

pub enum Expr<'a> {
     Var(&'a [u8]),
     Filter(&'a str, Box<Expr<'a>>),
}

pub enum Node<'a> {
    Lit(&'a [u8]),
    Expr(Expr<'a>),
    Cond(Vec<(Option<Expr<'a>>, Vec<Node<'a>>)>),
}

pub type Nodes<'a> = Vec<Node<'a>>;
pub type Conds<'a> = Vec<(Option<Expr<'a>>, Nodes<'a>)>;

fn take_content(i: &[u8]) -> IResult<&[u8], Node> {
    if i.len() < 1 || i[0] == b'{' {
        return IResult::Error(error_position!(nom::ErrorKind::TakeUntil, i));
    }
    for (j, c) in i.iter().enumerate() {
        if *c == b'{' {
            if i.len() < j + 2 {
                return IResult::Done(&i[..0], Node::Lit(&i[..]));
            } else if i[j + 1] == '{' as u8 {
                return IResult::Done(&i[j..], Node::Lit(&i[..j]));
            } else if i[j + 1] == '%' as u8 {
                return IResult::Done(&i[j..], Node::Lit(&i[..j]));
            }
        }
    }
    IResult::Done(&i[..0], Node::Lit(&i[..]))
}

named!(expr_var<Expr>, map!(nom::alphanumeric, Expr::Var));

fn expr_filtered(i: &[u8]) -> IResult<&[u8], Expr> {
    let (mut left, mut expr) = match expr_var(i) {
        IResult::Error(err) => { return IResult::Error(err); },
        IResult::Incomplete(needed) => { return IResult::Incomplete(needed); },
        IResult::Done(left, res) => (left, res),
    };
    while left[0] == b'|' {
        match nom::alphanumeric(&left[1..]) {
            IResult::Error(err) => {
                return IResult::Error(err);
            },
            IResult::Incomplete(needed) => {
                return IResult::Incomplete(needed);
            },
            IResult::Done(new_left, res) => {
                left = new_left;
                expr = Expr::Filter(str::from_utf8(res).unwrap(), Box::new(expr));
            },
        };
    }
    return IResult::Done(left, expr);
}

named!(expr_node<Node>, map!(
    delimited!(tag_s!("{{"), ws!(expr_filtered), tag_s!("}}")),
    Node::Expr));

named!(cond_elif<(Option<Expr>, Nodes)>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("elif")) >>
    cond: ws!(expr_filtered) >>
    tag_s!("%}") >>
    block: parse_template >>
    (Some(cond), block)));

named!(cond_else<Nodes>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("else")) >>
    tag_s!("%}") >>
    block: parse_template >>
    (block)));

named!(block_if<Node>, do_parse!(
    tag_s!("{%") >>
    ws!(tag_s!("if")) >>
    cond: ws!(expr_filtered) >>
    tag_s!("%}") >>
    block: parse_template >>
    elifs: many0!(cond_elif) >>
    rest: opt!(cond_else) >>
    tag_s!("{%") >>
    ws!(tag_s!("endif")) >>
    tag_s!("%}") >>
    ({
        let mut res = Vec::new();
        res.push((Some(cond), block));
        res.extend(elifs);
        if let Some(else_block) = rest {
            res.push((None, else_block));
        }
        Node::Cond(res)
    })));

named!(parse_template<Nodes>, many1!(alt!(
    take_content |
    expr_node |
    block_if)));

pub fn parse<'a>(src: &'a str) -> Nodes {
    match parse_template(src.as_bytes()) {
        IResult::Done(_, res) => res,
        IResult::Error(err) => panic!("problems parsing template source: {}", err),
        IResult::Incomplete(_) => panic!("parsing incomplete"),
    }
}
<|endoftext|>


<commit_before>//
// Copyright 2022 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use std::{fs, path::PathBuf};

use clap::Parser;
use futures::{stream::StreamExt, SinkExt};
use qemu::{Qemu, QemuParams};
use tokio::{io::AsyncReadExt, net::UnixStream, signal};
use tokio_serde_cbor::Codec;
use tokio_util::codec::Decoder;

mod qemu;
mod server;

#[derive(clap::ArgEnum, Clone, Debug, PartialEq)]
enum Mode {
    Uefi,
    Bios,
}

#[derive(Parser, Debug)]
struct Args {
    /// Path to the `qemu-system-x86_64` binary.
    #[clap(long, parse(from_os_str), validator = path_exists, default_value_os_t = PathBuf::from("/usr/bin/qemu-system-x86_64"))]
    qemu: PathBuf,

    /// Execute either in UEFI mode or BIOS mode.
    #[clap(arg_enum, long, default_value = "uefi")]
    mode: Mode,

    /// Path to the OVMF firmware file.
    #[clap(long, parse(from_os_str), required_if_eq("mode", "uefi"), validator = path_exists, default_value_os_t = PathBuf::from("/usr/share/OVMF/OVMF_CODE.fd"))]
    ovmf: PathBuf,

    /// Path to the UEFI app to execute.
    #[clap(parse(from_os_str), validator = path_exists)]
    app: PathBuf,
}

fn path_exists(s: &str) -> Result<(), String> {
    if !fs::metadata(s).map_err(|err| err.to_string())?.is_file() {
        Err(String::from("Path does not represent a file"))
    } else {
        Ok(())
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cli = Args::parse();
    env_logger::init();

    let (console_qemu, console) = UnixStream::pair()?;
    let (comms_qemu, mut comms) = UnixStream::pair()?;

    let mut qemu = Qemu::start(QemuParams {
        binary: cli.qemu.as_path(),
        firmware: if cli.mode == Mode::Uefi {
            Some(cli.ovmf.as_path())
        } else {
            None
        },
        app: cli.app.as_path(),
        console: console_qemu,
        comms: comms_qemu,
    })?;

    // Log everything coming over the console channel.
    tokio::spawn(async {
        let codec = tokio_util::codec::LinesCodec::new();
        let mut framed = codec.framed(console);

        while let Some(line) = framed.next().await {
            // The UEFI console uses ANSI escape codes to clear screen and set colours, so
            // let's not just print the string out but rather the debug version of that.
            log::info!("console: {:?}", line.unwrap())
        }
    });

    // TODO(#2709): Unfortunately OVMF writes some garbage (clear screen etc?) + our Hello
    // World to the other serial port, so let's skip some bytes before we set up the CBOR codec.
    // The length of 71 characters has been determined experimentally and will change if we
    // change what we write to stdout in the UEFI app.
    if cli.mode == Mode::Uefi {
        let mut junk = [0; 71];
        let mut len = 0;
        while len < junk.len() {
            len += comms.read(&mut junk[len..]).await.unwrap();
        }
        log::info!("Leading junk on comms: {:?}", std::str::from_utf8(&junk));
    }

    // Use a bmrng channel for serial communication. The good thing about spawning a separate
    // task for the serial communication is that it serializes (no pun intended) the communication,
    // as right now we don't have any mechanisms to track multiple requests in flight.
    let (tx, mut rx) = bmrng::unbounded_channel::<Vec<u8>, anyhow::Result<Vec<u8>>>();

    tokio::spawn(async move {
        // Set up the CBOR codec to handle the comms.
        let codec: Codec<Vec<u8>, Vec<u8>> = Codec::new();
        let mut channel = codec.framed(comms);
        while let Ok((input, responder)) = rx.recv().await {
            responder
                .respond({
                    if let Err(err) = channel.send(input).await {
                        Err(anyhow::Error::from(err))
                    } else {
                        // TODO(#2726): Sometimes next() gives us a None. Figure out what's going on
                        // in there.
                        let mut response;
                        loop {
                            response = channel.next().await;
                            if response.is_some() {
                                break;
                            }
                        }
                        response.unwrap().map_err(anyhow::Error::from)
                    }
                })
                .unwrap();
        }
    });

    let server_future = server::server("127.0.0.1:8000".parse()?, tx);

    // Wait until something dies or we get a signal to terminate.
    tokio::select! {
        _ = signal::ctrl_c() => {
            qemu.kill().await?;
        },
        _ = server_future => {
            qemu.kill().await?;
        },
        val = qemu.wait() => {
            log::error!("Unexpected qemu exit, status: {:?}", val);
        },
    }
    Ok(())
}
<commit_msg>Reading the comms serial port: Improve readability a bit (#2807)<commit_after>//
// Copyright 2022 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use std::{fs, path::PathBuf};

use clap::Parser;
use futures::{stream::StreamExt, SinkExt};
use qemu::{Qemu, QemuParams};
use tokio::{io::AsyncReadExt, net::UnixStream, signal};
use tokio_serde_cbor::Codec;
use tokio_util::codec::Decoder;

mod qemu;
mod server;

#[derive(clap::ArgEnum, Clone, Debug, PartialEq)]
enum Mode {
    Uefi,
    Bios,
}

#[derive(Parser, Debug)]
struct Args {
    /// Path to the `qemu-system-x86_64` binary.
    #[clap(long, parse(from_os_str), validator = path_exists, default_value_os_t = PathBuf::from("/usr/bin/qemu-system-x86_64"))]
    qemu: PathBuf,

    /// Execute either in UEFI mode or BIOS mode.
    #[clap(arg_enum, long, default_value = "uefi")]
    mode: Mode,

    /// Path to the OVMF firmware file.
    #[clap(long, parse(from_os_str), required_if_eq("mode", "uefi"), validator = path_exists, default_value_os_t = PathBuf::from("/usr/share/OVMF/OVMF_CODE.fd"))]
    ovmf: PathBuf,

    /// Path to the UEFI app to execute.
    #[clap(parse(from_os_str), validator = path_exists)]
    app: PathBuf,
}

fn path_exists(s: &str) -> Result<(), String> {
    if !fs::metadata(s).map_err(|err| err.to_string())?.is_file() {
        Err(String::from("Path does not represent a file"))
    } else {
        Ok(())
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cli = Args::parse();
    env_logger::init();

    let (console_qemu, console) = UnixStream::pair()?;
    let (comms_qemu, mut comms) = UnixStream::pair()?;

    let mut qemu = Qemu::start(QemuParams {
        binary: cli.qemu.as_path(),
        firmware: if cli.mode == Mode::Uefi {
            Some(cli.ovmf.as_path())
        } else {
            None
        },
        app: cli.app.as_path(),
        console: console_qemu,
        comms: comms_qemu,
    })?;

    // Log everything coming over the console channel.
    tokio::spawn(async {
        let codec = tokio_util::codec::LinesCodec::new();
        let mut framed = codec.framed(console);

        while let Some(line) = framed.next().await {
            // The UEFI console uses ANSI escape codes to clear screen and set colours, so
            // let's not just print the string out but rather the debug version of that.
            log::info!("console: {:?}", line.unwrap())
        }
    });

    // TODO(#2709): Unfortunately OVMF writes some garbage (clear screen etc?) + our Hello
    // World to the other serial port, so let's skip some bytes before we set up the CBOR codec.
    // The length of 71 characters has been determined experimentally and will change if we
    // change what we write to stdout in the UEFI app.
    if cli.mode == Mode::Uefi {
        let mut junk = [0; 71];
        comms.read_exact(&mut junk).await.unwrap();
        log::info!("Leading junk on comms: {:?}", std::str::from_utf8(&junk));
    }

    // Use a bmrng channel for serial communication. The good thing about spawning a separate
    // task for the serial communication is that it serializes (no pun intended) the communication,
    // as right now we don't have any mechanisms to track multiple requests in flight.
    let (tx, mut rx) = bmrng::unbounded_channel::<Vec<u8>, anyhow::Result<Vec<u8>>>();

    tokio::spawn(async move {
        // Set up the CBOR codec to handle the comms.
        let codec: Codec<Vec<u8>, Vec<u8>> = Codec::new();
        let mut channel = codec.framed(comms);
        while let Ok((input, responder)) = rx.recv().await {
            responder
                .respond({
                    if let Err(err) = channel.send(input).await {
                        Err(anyhow::Error::from(err))
                    } else {
                        // TODO(#2726): Sometimes next() gives us a None. Figure out what's going on
                        // in there.
                        let mut response;
                        loop {
                            response = channel.next().await;
                            if response.is_some() {
                                break;
                            }
                        }
                        response.unwrap().map_err(anyhow::Error::from)
                    }
                })
                .unwrap();
        }
    });

    let server_future = server::server("127.0.0.1:8000".parse()?, tx);

    // Wait until something dies or we get a signal to terminate.
    tokio::select! {
        _ = signal::ctrl_c() => {
            qemu.kill().await?;
        },
        _ = server_future => {
            qemu.kill().await?;
        },
        val = qemu.wait() => {
            log::error!("Unexpected qemu exit, status: {:?}", val);
        },
    }
    Ok(())
}
<|endoftext|>