<commit_before>use std::{collections::BTreeMap, convert::TryInto, fmt, panic};

use quickcheck::{Arbitrary, Gen, RngCore};
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand_distr::{Distribution, Gamma};

use sled::*;

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Key(pub Vec<u8>);

impl fmt::Debug for Key {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Key(vec!{:?})", self.0)
    }
}

struct SledGen {
    r: StdRng,
    size: usize,
}

impl Gen for SledGen {
    fn size(&self) -> usize {
        self.size
    }
}

impl RngCore for SledGen {
    fn next_u32(&mut self) -> u32 {
        self.r.gen::<u32>()
    }

    fn next_u64(&mut self) -> u64 {
        self.r.gen::<u64>()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.r.fill_bytes(dest)
    }

    fn try_fill_bytes(
        &mut self,
        dest: &mut [u8],
    ) -> std::result::Result<(), rand::Error> {
        self.r.try_fill_bytes(dest)
    }
}

pub fn fuzz_then_shrink(buf: &[u8]) {
    let use_compression =
        cfg!(feature = "compression") && buf.get(0).unwrap_or(&0) % 2 == 0;

    let ops: Vec<Op> = buf
        .chunks(2)
        .map(|chunk| {
            let mut seed = [0_u8; 32];
            seed[0..chunk.len()].copy_from_slice(chunk);
            let rng: StdRng = SeedableRng::from_seed(seed);
            let mut sled_rng = SledGen { r: rng, size: 2 };

            Op::arbitrary(&mut sled_rng)
        })
        .collect();

    match panic::catch_unwind(move || {
        prop_tree_matches_btreemap(ops, 100, false, use_compression)
    }) {
        Ok(_) => {}
        Err(_e) => panic!("TODO"),
    }
}

impl Arbitrary for Key {
    #![allow(clippy::cast_possible_truncation)]
    #![allow(clippy::cast_precision_loss)]
    #![allow(clippy::cast_sign_loss)]

    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        if g.gen::<bool>() {
            let gs = g.size();
            let gamma = Gamma::new(0.3, gs as f64).unwrap();
            let v = gamma.sample(&mut rand::thread_rng());
            let len = if v > 3000.0 { 10000 } else { (v % 300.) as usize };

            let space = g.gen_range(0, gs) + 1;

            let inner = (0..len).map(|_| g.gen_range(0, space) as u8).collect();

            Self(inner)
        } else {
            let len = g.gen_range(0, 2);
            let mut inner = vec![];

            for _ in 0..len {
                inner.push(g.gen::<u8>());
            }

            Self(inner)
        }
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        // we only want to shrink on length, not byte values
        Box::new(
            self.0
                .len()
                .shrink()
                .zip(std::iter::repeat(self.0.clone()))
                .map(|(len, underlying)| Self(underlying[..len].to_vec())),
        )
    }
}

#[derive(Debug, Clone)]
pub enum Op {
    Set(Key, u8),
    Merge(Key, u8),
    Get(Key),
    GetLt(Key),
    GetGt(Key),
    Del(Key),
    Cas(Key, u8, u8),
    Scan(Key, isize),
    Restart,
}

use self::Op::{Cas, Del, Get, GetGt, GetLt, Merge, Restart, Scan, Set};

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        if g.gen_bool(1. / 10.) {
            return Restart;
        }

        let choice = g.gen_range(0, 8);

        match choice {
            0 => Set(Key::arbitrary(g), g.gen::<u8>()),
            1 => Merge(Key::arbitrary(g), g.gen::<u8>()),
            2 => Get(Key::arbitrary(g)),
            3 => GetLt(Key::arbitrary(g)),
            4 => GetGt(Key::arbitrary(g)),
            5 => Del(Key::arbitrary(g)),
            6 => Cas(Key::arbitrary(g), g.gen::<u8>(), g.gen::<u8>()),
            7 => Scan(Key::arbitrary(g), g.gen_range(-40, 40)),
            _ => panic!("impossible choice"),
        }
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        match *self {
            Set(ref k, v) => Box::new(k.shrink().map(move |sk| Set(sk, v))),
            Merge(ref k, v) => Box::new(k.shrink().flat_map(move |k| {
                vec![Set(k.clone(), v.clone()), Merge(k, v)]
            })),
            Get(ref k) => Box::new(k.shrink().map(Get)),
            GetLt(ref k) => Box::new(k.shrink().map(GetLt)),
            GetGt(ref k) => Box::new(k.shrink().map(GetGt)),
            Cas(ref k, old, new) => {
                Box::new(k.shrink().map(move |k| Cas(k, old, new)))
            }
            Scan(ref k, len) => Box::new(k.shrink().map(move |k| Scan(k, len))),
            Del(ref k) => Box::new(k.shrink().map(Del)),
            Restart => Box::new(vec![].into_iter()),
        }
    }
}

fn bytes_to_u16(v: &[u8]) -> u16 {
    assert_eq!(v.len(), 2);
    (u16::from(v[0]) << 8) + u16::from(v[1])
}

fn u16_to_bytes(u: u16) -> Vec<u8> {
    u.to_be_bytes().to_vec()
}

// just adds up values as if they were u16's
fn test_merge_operator(
    _k: &[u8],
    old: Option<&[u8]>,
    to_merge: &[u8],
) -> Option<Vec<u8>> {
    let base = old.unwrap_or(&[0, 0]);
    let base_n = bytes_to_u16(base);
    let new_n = base_n + u16::from(to_merge[0]);
    let ret = u16_to_bytes(new_n);
    Some(ret)
}

pub fn prop_tree_matches_btreemap(
    ops: Vec<Op>,
    snapshot_after: u8,
    flusher: bool,
    use_compression: bool,
) -> bool {
    use self::*;

    super::common::setup_logger();

    let use_compression = cfg!(feature = "compression") && use_compression;

    let config = Config::new()
        .temporary(true)
        .use_compression(use_compression)
        .snapshot_after_ops(u64::from(snapshot_after) + 1)
        .flush_every_ms(if flusher { Some(1) } else { None })
        .cache_capacity(256)
        .idgen_persist_interval(1)
        .segment_size(8192);

    let mut tree = config.open().unwrap();
    tree.set_merge_operator(test_merge_operator);

    let mut reference: BTreeMap<Key, u16> = BTreeMap::new();

    for op in ops {
        match op {
            Set(k, v) => {
                let old_actual = tree.insert(&k.0, vec![0, v]).unwrap();
                let old_reference = reference.insert(k.clone(), u16::from(v));
                assert_eq!(
                    old_actual.map(|v| bytes_to_u16(&*v)),
                    old_reference,
                    "when setting key {:?}, expected old returned value to be {:?}\n{:?}",
                    k,
                    old_reference,
                    tree
                );
            }
            Merge(k, v) => {
                tree.merge(&k.0, vec![v]).unwrap();
                let entry = reference.entry(k).or_insert(0_u16);
                *entry += u16::from(v);
            }
            Get(k) => {
                let res1 = tree.get(&*k.0).unwrap().map(|v| bytes_to_u16(&*v));
                let res2 = reference.get(&k).cloned();
                assert_eq!(res1, res2);
            }
            GetLt(k) => {
                let res1 = tree.get_lt(&*k.0).unwrap().map(|v| v.0);
                let res2 = reference
                    .iter()
                    .rev()
                    .filter(|(key, _)| **key < k)
                    .nth(0)
                    .map(|(k, _v)| IVec::from(&*k.0));
                assert_eq!(
                    res1, res2,
                    "get_lt({:?}) should have returned {:?} \
                     but it returned {:?} instead. \
                     \n Db: {:?}",
                    k, res2, res1, tree
                );
            }
            GetGt(k) => {
                let res1 = tree.get_gt(&*k.0).unwrap().map(|v| v.0);
                let res2 = reference
                    .iter()
                    .filter(|(key, _)| **key > k)
                    .nth(0)
                    .map(|(k, _v)| IVec::from(&*k.0));
                assert_eq!(
                    res1, res2,
                    "get_gt({:?}) expected {:?} in tree {:?}",
                    k, res2, tree
                );
            }
            Del(k) => {
                tree.remove(&*k.0).unwrap();
                reference.remove(&k);
            }
            Cas(k, old, new) => {
                let tree_old = tree.get(&*k.0).unwrap();
                if let Some(old_tree) = tree_old {
                    if old_tree == *vec![0, old] {
                        tree.insert(&k.0, vec![0, new]).unwrap();
                    }
                }

                let ref_old = reference.get(&k).cloned();
                if ref_old == Some(u16::from(old)) {
                    reference.insert(k, u16::from(new));
                }
            }
            Scan(k, len) => {
                if len > 0 {
                    let mut tree_iter = tree
                        .range(&*k.0..)
                        .take(len.abs().try_into().unwrap())
                        .map(Result::unwrap);
                    let ref_iter = reference
                        .iter()
                        .filter(|&(ref rk, _rv)| **rk >= k)
                        .take(len.abs().try_into().unwrap())
                        .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                    for r in ref_iter {
                        let tree_next = tree_iter.next().unwrap();
                        let lhs = (tree_next.0, &*tree_next.1);
                        let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                        assert_eq!(
                            (lhs.0.as_ref(), lhs.1),
                            (rhs.0.as_ref(), rhs.1),
                            "expected {:?} while iterating from {:?} on tree: {:?}",
                            rhs,
                            k,
                            tree
                        );
                    }
                } else {
                    let mut tree_iter = tree
                        .range(&*k.0..)
                        .rev()
                        .take(len.abs().try_into().unwrap())
                        .map(Result::unwrap);
                    let ref_iter = reference
                        .iter()
                        .rev()
                        .filter(|&(ref rk, _rv)| **rk >= k)
                        .take(len.abs().try_into().unwrap())
                        .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                    for r in ref_iter {
                        let tree_next = tree_iter.next().unwrap();
                        let lhs = (tree_next.0, &*tree_next.1);
                        let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                        assert_eq!(
                            (lhs.0.as_ref(), lhs.1),
                            (rhs.0.as_ref(), rhs.1),
                            "expected {:?} while reverse iterating from {:?} on tree: {:?}",
                            rhs,
                            k,
                            tree
                        );
                    }
                }
            }
            Restart => {
                drop(tree);
                tree = config.open().unwrap();
                tree.set_merge_operator(test_merge_operator);
            }
        }
    }

    let space_amplification = tree
        .space_amplification()
        .expect("should be able to read files and pages");

    assert!(
        space_amplification < MAX_SPACE_AMPLIFICATION,
        "space amplification was measured to be {}, \
         which is higher than the maximum of {}",
        space_amplification,
        MAX_SPACE_AMPLIFICATION
    );

    true
}

#[test]
fn test_fuzz_test() {
    let seed = [0; 32];
    fuzz_then_shrink(&seed);
    let seed = [0; 31];
    fuzz_then_shrink(&seed);
    let seed = [0; 33];
    fuzz_then_shrink(&seed);
    fuzz_then_shrink(&[]);
}
<commit_msg>Improve tree test<commit_after>use std::{collections::BTreeMap, convert::TryInto, fmt, panic};

use quickcheck::{Arbitrary, Gen, RngCore};
use rand::{rngs::StdRng, Rng, SeedableRng};
use rand_distr::{Distribution, Gamma};

use sled::*;

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Key(pub Vec<u8>);

impl fmt::Debug for Key {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Key(vec!{:?})", self.0)
    }
}

struct SledGen {
    r: StdRng,
    size: usize,
}

impl Gen for SledGen {
    fn size(&self) -> usize {
        self.size
    }
}

impl RngCore for SledGen {
    fn next_u32(&mut self) -> u32 {
        self.r.gen::<u32>()
    }

    fn next_u64(&mut self) -> u64 {
        self.r.gen::<u64>()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.r.fill_bytes(dest)
    }

    fn try_fill_bytes(
        &mut self,
        dest: &mut [u8],
    ) -> std::result::Result<(), rand::Error> {
        self.r.try_fill_bytes(dest)
    }
}

pub fn fuzz_then_shrink(buf: &[u8]) {
    let use_compression =
        cfg!(feature = "compression") && buf.get(0).unwrap_or(&0) % 2 == 0;

    let ops: Vec<Op> = buf
        .chunks(2)
        .map(|chunk| {
            let mut seed = [0_u8; 32];
            seed[0..chunk.len()].copy_from_slice(chunk);
            let rng: StdRng = SeedableRng::from_seed(seed);
            let mut sled_rng = SledGen { r: rng, size: 2 };

            Op::arbitrary(&mut sled_rng)
        })
        .collect();

    match panic::catch_unwind(move || {
        prop_tree_matches_btreemap(ops, 100, false, use_compression)
    }) {
        Ok(_) => {}
        Err(_e) => panic!("TODO"),
    }
}

impl Arbitrary for Key {
    #![allow(clippy::cast_possible_truncation)]
    #![allow(clippy::cast_precision_loss)]
    #![allow(clippy::cast_sign_loss)]

    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        if g.gen::<bool>() {
            let gs = g.size();
            let gamma = Gamma::new(0.3, gs as f64).unwrap();
            let v = gamma.sample(&mut rand::thread_rng());
            let len = if v > 3000.0 { 10000 } else { (v % 300.) as usize };

            let space = g.gen_range(0, gs) + 1;

            let inner = (0..len).map(|_| g.gen_range(0, space) as u8).collect();

            Self(inner)
        } else {
            let len = g.gen_range(0, 2);
            let mut inner = vec![];

            for _ in 0..len {
                inner.push(g.gen::<u8>());
            }

            Self(inner)
        }
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        // we only want to shrink on length, not byte values
        Box::new(
            self.0
                .len()
                .shrink()
                .zip(std::iter::repeat(self.0.clone()))
                .map(|(len, underlying)| Self(underlying[..len].to_vec())),
        )
    }
}

#[derive(Debug, Clone)]
pub enum Op {
    Set(Key, u8),
    Merge(Key, u8),
    Get(Key),
    GetLt(Key),
    GetGt(Key),
    Del(Key),
    Cas(Key, u8, u8),
    Scan(Key, isize),
    Restart,
}

use self::Op::{Cas, Del, Get, GetGt, GetLt, Merge, Restart, Scan, Set};

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        if g.gen_bool(1. / 10.) {
            return Restart;
        }

        let choice = g.gen_range(0, 8);

        match choice {
            0 => Set(Key::arbitrary(g), g.gen::<u8>()),
            1 => Merge(Key::arbitrary(g), g.gen::<u8>()),
            2 => Get(Key::arbitrary(g)),
            3 => GetLt(Key::arbitrary(g)),
            4 => GetGt(Key::arbitrary(g)),
            5 => Del(Key::arbitrary(g)),
            6 => Cas(Key::arbitrary(g), g.gen::<u8>(), g.gen::<u8>()),
            7 => Scan(Key::arbitrary(g), g.gen_range(-40, 40)),
            _ => panic!("impossible choice"),
        }
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        match *self {
            Set(ref k, v) => Box::new(k.shrink().map(move |sk| Set(sk, v))),
            Merge(ref k, v) => Box::new(k.shrink().flat_map(move |k| {
                vec![Set(k.clone(), v.clone()), Merge(k, v)]
            })),
            Get(ref k) => Box::new(k.shrink().map(Get)),
            GetLt(ref k) => Box::new(k.shrink().map(GetLt)),
            GetGt(ref k) => Box::new(k.shrink().map(GetGt)),
            Cas(ref k, old, new) => {
                Box::new(k.shrink().map(move |k| Cas(k, old, new)))
            }
            Scan(ref k, len) => Box::new(k.shrink().map(move |k| Scan(k, len))),
            Del(ref k) => Box::new(k.shrink().map(Del)),
            Restart => Box::new(vec![].into_iter()),
        }
    }
}

fn bytes_to_u16(v: &[u8]) -> u16 {
    assert_eq!(v.len(), 2);
    (u16::from(v[0]) << 8) + u16::from(v[1])
}

fn u16_to_bytes(u: u16) -> Vec<u8> {
    u.to_be_bytes().to_vec()
}

// just adds up values as if they were u16's
fn test_merge_operator(
    _k: &[u8],
    old: Option<&[u8]>,
    to_merge: &[u8],
) -> Option<Vec<u8>> {
    let base = old.unwrap_or(&[0, 0]);
    let base_n = bytes_to_u16(base);
    let new_n = base_n + u16::from(to_merge[0]);
    let ret = u16_to_bytes(new_n);
    Some(ret)
}

pub fn prop_tree_matches_btreemap(
    ops: Vec<Op>,
    snapshot_after: u8,
    flusher: bool,
    use_compression: bool,
) -> bool {
    if let Err(e) = prop_tree_matches_btreemap_inner(
        ops,
        snapshot_after,
        flusher,
        use_compression,
    ) {
        eprintln!("hit error while running quickcheck on tree: {:?}", e);
        false
    } else {
        true
    }
}

fn prop_tree_matches_btreemap_inner(
    ops: Vec<Op>,
    snapshot_after: u8,
    flusher: bool,
    use_compression: bool,
) -> Result<()> {
    use self::*;

    super::common::setup_logger();

    let use_compression = cfg!(feature = "compression") && use_compression;

    let config = Config::new()
        .temporary(true)
        .use_compression(use_compression)
        .snapshot_after_ops(u64::from(snapshot_after) + 1)
        .flush_every_ms(if flusher { Some(1) } else { None })
        .cache_capacity(256)
        .idgen_persist_interval(1)
        .segment_size(8192);

    let mut tree = config.open().unwrap();
    tree.set_merge_operator(test_merge_operator);

    let mut reference: BTreeMap<Key, u16> = BTreeMap::new();

    for op in ops {
        match op {
            Set(k, v) => {
                let old_actual = tree.insert(&k.0, vec![0, v]).unwrap();
                let old_reference = reference.insert(k.clone(), u16::from(v));
                assert_eq!(
                    old_actual.map(|v| bytes_to_u16(&*v)),
                    old_reference,
                    "when setting key {:?}, expected old returned value to be {:?}\n{:?}",
                    k,
                    old_reference,
                    tree
                );
            }
            Merge(k, v) => {
                tree.merge(&k.0, vec![v]).unwrap();
                let entry = reference.entry(k).or_insert(0_u16);
                *entry += u16::from(v);
            }
            Get(k) => {
                let res1 = tree.get(&*k.0).unwrap().map(|v| bytes_to_u16(&*v));
                let res2 = reference.get(&k).cloned();
                assert_eq!(res1, res2);
            }
            GetLt(k) => {
                let res1 = tree.get_lt(&*k.0).unwrap().map(|v| v.0);
                let res2 = reference
                    .iter()
                    .rev()
                    .filter(|(key, _)| **key < k)
                    .nth(0)
                    .map(|(k, _v)| IVec::from(&*k.0));
                assert_eq!(
                    res1, res2,
                    "get_lt({:?}) should have returned {:?} \
                     but it returned {:?} instead. \
                     \n Db: {:?}",
                    k, res2, res1, tree
                );
            }
            GetGt(k) => {
                let res1 = tree.get_gt(&*k.0).unwrap().map(|v| v.0);
                let res2 = reference
                    .iter()
                    .filter(|(key, _)| **key > k)
                    .nth(0)
                    .map(|(k, _v)| IVec::from(&*k.0));
                assert_eq!(
                    res1, res2,
                    "get_gt({:?}) expected {:?} in tree {:?}",
                    k, res2, tree
                );
            }
            Del(k) => {
                tree.remove(&*k.0).unwrap();
                reference.remove(&k);
            }
            Cas(k, old, new) => {
                let tree_old = tree.get(&*k.0).unwrap();
                if let Some(old_tree) = tree_old {
                    if old_tree == *vec![0, old] {
                        tree.insert(&k.0, vec![0, new]).unwrap();
                    }
                }

                let ref_old = reference.get(&k).cloned();
                if ref_old == Some(u16::from(old)) {
                    reference.insert(k, u16::from(new));
                }
            }
            Scan(k, len) => {
                if len > 0 {
                    let mut tree_iter = tree
                        .range(&*k.0..)
                        .take(len.abs().try_into().unwrap())
                        .map(Result::unwrap);
                    let ref_iter = reference
                        .iter()
                        .filter(|&(ref rk, _rv)| **rk >= k)
                        .take(len.abs().try_into().unwrap())
                        .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                    for r in ref_iter {
                        let tree_next = tree_iter.next().unwrap();
                        let lhs = (tree_next.0, &*tree_next.1);
                        let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                        assert_eq!(
                            (lhs.0.as_ref(), lhs.1),
                            (rhs.0.as_ref(), rhs.1),
                            "expected {:?} while iterating from {:?} on tree: {:?}",
                            rhs,
                            k,
                            tree
                        );
                    }
                } else {
                    let mut tree_iter = tree
                        .range(&*k.0..)
                        .rev()
                        .take(len.abs().try_into().unwrap())
                        .map(Result::unwrap);
                    let ref_iter = reference
                        .iter()
                        .rev()
                        .filter(|&(ref rk, _rv)| **rk >= k)
                        .take(len.abs().try_into().unwrap())
                        .map(|(ref rk, ref rv)| (rk.0.clone(), **rv));

                    for r in ref_iter {
                        let tree_next = tree_iter.next().unwrap();
                        let lhs = (tree_next.0, &*tree_next.1);
                        let rhs = (r.0.clone(), &*u16_to_bytes(r.1));
                        assert_eq!(
                            (lhs.0.as_ref(), lhs.1),
                            (rhs.0.as_ref(), rhs.1),
                            "expected {:?} while reverse iterating from {:?} on tree: {:?}",
                            rhs,
                            k,
                            tree
                        );
                    }
                }
            }
            Restart => {
                drop(tree);
                tree = config.open().unwrap();
                tree.set_merge_operator(test_merge_operator);
            }
        }
        if let Err(e) = config.global_error() {
            eprintln!("quickcheck test encountered error: {:?}", e);
            return Err(e);
        }
    }

    let space_amplification = tree
        .space_amplification()
        .expect("should be able to read files and pages");

    assert!(
        space_amplification < MAX_SPACE_AMPLIFICATION,
        "space amplification was measured to be {}, \
         which is higher than the maximum of {}",
        space_amplification,
        MAX_SPACE_AMPLIFICATION
    );

    drop(tree);
    config.global_error()
}

#[test]
fn test_fuzz_test() {
    let seed = [0; 32];
    fuzz_then_shrink(&seed);
    let seed = [0; 31];
    fuzz_then_shrink(&seed);
    let seed = [0; 33];
    fuzz_then_shrink(&seed);
    fuzz_then_shrink(&[]);
}
<|endoftext|>


<commit_before>use super::*;

impl Editor {
    /// Go to next char
    pub fn next(&mut self) {
        if self.x() == self.text[self.y()].len() {
            if self.y() >= self.text.len() {
                self.text.push_back(VecDeque::new())
            }
            if self.y() < self.text.len() - 1 {
                self.cursor_mut().x = 0;
                self.cursor_mut().y += 1;
            }

        } else {
            self.cursor_mut().x += 1;
        }
    }

    /// Go to previous char
    pub fn previous(&mut self) {
        if self.x() == 0 {
            if self.y() > 0 {
                self.cursor_mut().y -= 1;
                self.cursor_mut().x = self.text[self.y() - 1].len();
            }
        } else {
            self.cursor_mut().y -= 1;
        }

    }

    /// Go right
    pub fn right(&mut self, n: usize) {
        let x = self.x() + n;
        let y = self.y();

        let text = self.text.clone();
        let curs = self.cursor_mut();

        curs.x += n;

        if x > text[y].len() {
            curs.x = text[y].len();
        }
    }
    /// Go left
    pub fn left(&mut self, n: usize) {
        let x = self.x();
        let y = self.y();

        let text = self.text.clone();
        let curs = self.cursor_mut();

        if n <= x {
            curs.x = x - n;
        } else {
            curs.x = 0;
        }

    }
    /// Go up
    pub fn up(&mut self, n: usize) {
        let y = self.y();
        let curs = self.cursor_mut();
        if n <= y {
            curs.y -= n;
        } else {
            curs.y = 0;
        }
    }
    /// Go down
    pub fn down(&mut self, n: usize) {
        let x = self.x();
        let y = self.y() + n;

        let text = self.text.clone();
        let curs = self.cursor_mut();

        curs.y += n;

        if y >= text.len() {
            curs.y = text.len() - 1;
        }
    }
}
<commit_msg>Fix backspace<commit_after>use super::*;

impl Editor {
    /// Go to next char
    pub fn next(&mut self) {
        if self.x() == self.text[self.y()].len() {
            if self.y() >= self.text.len() {
                self.text.push_back(VecDeque::new())
            }
            if self.y() < self.text.len() - 1 {
                self.cursor_mut().x = 0;
                self.cursor_mut().y += 1;
            }

        } else {
            self.cursor_mut().x += 1;
        }
    }

    /// Go to previous char
    pub fn previous(&mut self) {
        if self.x() == 0 {
            if self.y() > 0 {
                self.cursor_mut().y -= 1;
                self.cursor_mut().x = self.text[self.y()].len();
            }
        } else {
            self.cursor_mut().x -= 1;
        }

    }

    /// Go right
    pub fn right(&mut self, n: usize) {
        let x = self.x() + n;
        let y = self.y();

        let text = self.text.clone();
        let curs = self.cursor_mut();

        curs.x += n;

        if x > text[y].len() {
            curs.x = text[y].len();
        }
    }
    /// Go left
    pub fn left(&mut self, n: usize) {
        let x = self.x();
        let y = self.y();

        let text = self.text.clone();
        let curs = self.cursor_mut();

        if n <= x {
            curs.x = x - n;
        } else {
            curs.x = 0;
        }

    }
    /// Go up
    pub fn up(&mut self, n: usize) {
        let y = self.y();
        let curs = self.cursor_mut();
        if n <= y {
            curs.y -= n;
        } else {
            curs.y = 0;
        }
    }
    /// Go down
    pub fn down(&mut self, n: usize) {
        let x = self.x();
        let y = self.y() + n;

        let text = self.text.clone();
        let curs = self.cursor_mut();

        curs.y += n;

        if y >= text.len() {
            curs.y = text.len() - 1;
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use font::FontHandleMethods;
use font_context::FontContextHandleMethods;
use font_list::{FontEntry, FontFamily, FontFamilyMap};
use platform::macos::font::FontHandle;
use platform::macos::font_context::FontContextHandle;

use core_foundation::base::TCFType;
use core_foundation::string::{CFString, CFStringRef};
use core_text;
use core_text::font_descriptor::{CTFontDescriptor, CTFontDescriptorRef};

use std::cast;
use std::hashmap::HashMap;

pub struct FontListHandle {
    fctx: FontContextHandle,
}

impl FontListHandle {
    pub fn new(fctx: &FontContextHandle) -> FontListHandle {
        FontListHandle {
            fctx: fctx.clone()
        }
    }

    pub fn get_available_families(&self) -> FontFamilyMap {
        let family_names = core_text::font_collection::get_family_names();
        let mut family_map: FontFamilyMap = HashMap::new();
        for strref in family_names.iter() {
            let family_name_ref: CFStringRef = unsafe { cast::transmute(strref) };
            let family_name_cf: CFString = unsafe { TCFType::wrap_under_get_rule(family_name_ref) };
            let family_name = family_name_cf.to_str();
            debug!("Creating new FontFamily for family: {:s}", family_name);

            let new_family = @mut FontFamily::new(family_name);
            family_map.insert(family_name, new_family);
        }
        family_map
    }

    pub fn load_variations_for_family(&self, family: @mut FontFamily) {
        debug!("Looking for faces of family: {:s}", family.family_name);

        let family_collection = core_text::font_collection::create_for_family(family.family_name);
        let family_descriptors = family_collection.get_descriptors();
        for descref in family_descriptors.iter() {
            let descref: CTFontDescriptorRef = unsafe { cast::transmute(descref) };
            let desc: CTFontDescriptor = unsafe { TCFType::wrap_under_get_rule(descref) };
            let font = core_text::font::new_from_descriptor(&desc, 0.0);
            let handle = FontHandle::new_from_CTFont(&self.fctx, font).unwrap();

            debug!("Creating new FontEntry for face: {:s}", handle.face_name());
            let entry = @FontEntry::new(handle);
            family.entries.push(entry)
        }
    }

    pub fn get_last_resort_font_families() -> ~[~str] {
        ~[~"Arial Unicode MS",~"Arial"]
    }
}
<commit_msg>Patch for macos<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use font::FontHandleMethods;
use font_context::FontContextHandleMethods;
use font_list::{FontEntry, FontFamily, FontFamilyMap};
use platform::macos::font::FontHandle;
use platform::macos::font_context::FontContextHandle;

use core_foundation::base::TCFType;
use core_foundation::string::{CFString, CFStringRef};
use core_text;
use core_text::font_descriptor::{CTFontDescriptor, CTFontDescriptorRef};

use std::cast;
use std::hashmap::HashMap;

pub struct FontListHandle {
    fctx: FontContextHandle,
}

impl FontListHandle {
    pub fn new(fctx: &FontContextHandle) -> FontListHandle {
        FontListHandle {
            fctx: fctx.clone()
        }
    }

    pub fn get_available_families(&self) -> FontFamilyMap {
        let family_names = core_text::font_collection::get_family_names();
        let mut family_map: FontFamilyMap = HashMap::new();
        for strref in family_names.iter() {
            let family_name_ref: CFStringRef = unsafe { cast::transmute(strref) };
            let family_name_cf: CFString = unsafe { TCFType::wrap_under_get_rule(family_name_ref) };
            let family_name = family_name_cf.to_str();
            debug!("Creating new FontFamily for family: {:s}", family_name);

            let new_family = FontFamily::new(family_name);
            family_map.insert(family_name, new_family);
        }
        family_map
    }

    pub fn load_variations_for_family(&self, family: &mut FontFamily) {
        debug!("Looking for faces of family: {:s}", family.family_name);

        let family_collection = core_text::font_collection::create_for_family(family.family_name);
        let family_descriptors = family_collection.get_descriptors();
        for descref in family_descriptors.iter() {
            let descref: CTFontDescriptorRef = unsafe { cast::transmute(descref) };
            let desc: CTFontDescriptor = unsafe { TCFType::wrap_under_get_rule(descref) };
            let font = core_text::font::new_from_descriptor(&desc, 0.0);
            let handle = FontHandle::new_from_CTFont(&self.fctx, font).unwrap();

            debug!("Creating new FontEntry for face: {:s}", handle.face_name());
            let entry = FontEntry::new(handle);
            family.entries.push(entry)
        }
    }

    pub fn get_last_resort_font_families() -> ~[~str] {
        ~[~"Arial Unicode MS",~"Arial"]
    }
}
<|endoftext|>


<commit_before><commit_msg>update comments<commit_after><|endoftext|>


<commit_before>/*!
Errors and error handling

This mostly concerns converting to and from the main error type defined
in this crate: [`Error`](enum.Error.html)
*/

use std::ffi::{IntoStringError, NulError};
use std::io;
use std::ops::Range;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::sync;
use stringutils::status_to_string;

/// Enumeration of all error types
#[derive(Debug)]
pub enum Error {
    /// Internal Fits errors
    Fits(FitsError),

    /// Invalid index error
    Index(IndexError),

    /// Generic errors from simple strings
    Message(String),

    /// String conversion errors
    Null(NulError),

    /// UTF-8 conversion errors
    Utf8(Utf8Error),

    /// IO errors
    Io(io::Error),

    /// String conversion errors
    IntoString(IntoStringError),

    /// File path already exists
    ExistingFile(String),

    /// Error unlocking a mutex
    UnlockError,
}

/// Error raised when the user requests invalid indexes for data
#[derive(Debug, PartialEq, Eq)]
pub struct IndexError {
    /// Error message
    pub message: String,

    /// The range requested by the user
    pub given: Range<usize>,
}

/// Handy error type for use internally
pub type Result<T> = ::std::result::Result<T, Error>;

impl ::std::convert::From<FitsError> for Error {
    fn from(error: FitsError) -> Self {
        Error::Fits(error)
    }
}

impl ::std::convert::From<IndexError> for Error {
    fn from(error: IndexError) -> Self {
        Error::Index(error)
    }
}

impl<'a> ::std::convert::From<&'a str> for Error {
    fn from(error: &'a str) -> Self {
        Error::Message(error.to_string())
    }
}

impl ::std::convert::From<NulError> for Error {
    fn from(error: NulError) -> Self {
        Error::Null(error)
    }
}

impl ::std::convert::From<FromUtf8Error> for Error {
    fn from(error: FromUtf8Error) -> Self {
        Error::Utf8(error.utf8_error())
    }
}

impl ::std::convert::From<Utf8Error> for Error {
    fn from(error: Utf8Error) -> Self {
        Error::Utf8(error)
    }
}

impl ::std::convert::From<Box<::std::error::Error>> for Error {
    fn from(error: Box<::std::error::Error>) -> Self {
        let description = error.description();
        let message = match error.cause() {
            Some(msg) => format!("Error: {} caused by {}", description, msg),
            None => format!("Error: {}", description),
        };
        Error::Message(message)
    }
}

impl ::std::convert::From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

impl ::std::convert::From<IntoStringError> for Error {
    fn from(e: IntoStringError) -> Self {
        Error::IntoString(e)
    }
}

use fitsfile::FitsFile;
type PoisonError<'a> = sync::PoisonError<sync::MutexGuard<'a, FitsFile>>;

impl<'a> ::std::convert::From<PoisonError<'a>> for Error {
    fn from(_e: PoisonError) -> Self {
        Error::UnlockError
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        match *self {
            Error::Fits(ref e) => write!(f, "Fits error: {:?}", e),
            Error::Message(ref s) => write!(f, "Error: {}", s),
            Error::Null(ref e) => e.fmt(f),
            Error::Utf8(ref e) => e.fmt(f),
            Error::Index(ref e) => write!(f, "Error: {:?}", e),
            Error::Io(ref e) => e.fmt(f),
            Error::IntoString(ref e) => e.fmt(f),
            Error::ExistingFile(ref filename) => write!(f, "File {} already exists", filename),
            Error::UnlockError => write!(f, "Invalid concurrent access to fits file"),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        "fitsio error"
    }
}

/**
Error type

`cfitsio` passes errors through integer status codes. This struct wraps this and its associated
error message.
*/
#[derive(Debug, PartialEq, Eq)]
pub struct FitsError {
    /// `cfitsio` error code
    pub status: i32,
    /// `cfitsio` message for error code
    pub message: String,
}

/// Function for chaining result types
pub fn check_status(status: i32) -> Result<()> {
    match status {
        0 => Ok(()),
        _ => Err(Error::Fits(FitsError {
            status,
            message: status_to_string(status)?.expect("guaranteed to be Some"),
        })),
    }
}

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

    #[test]
    fn test_check_status_ok() {
        assert!(check_status(0).is_ok());
    }

    #[test]
    fn test_check_status_ok_with_value() {
        assert_eq!(check_status(0).map(|_| 10i32).unwrap(), 10i32);
    }

    #[test]
    fn test_check_status_with_err() {
        assert!(check_status(105).map(|_| 10i32).is_err());
    }
}
<commit_msg>Prevent deprecation<commit_after>/*!
Errors and error handling

This mostly concerns converting to and from the main error type defined
in this crate: [`Error`](enum.Error.html)
*/

use std::ffi::{IntoStringError, NulError};
use std::io;
use std::ops::Range;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::sync;
use stringutils::status_to_string;

/// Enumeration of all error types
#[derive(Debug)]
pub enum Error {
    /// Internal Fits errors
    Fits(FitsError),

    /// Invalid index error
    Index(IndexError),

    /// Generic errors from simple strings
    Message(String),

    /// String conversion errors
    Null(NulError),

    /// UTF-8 conversion errors
    Utf8(Utf8Error),

    /// IO errors
    Io(io::Error),

    /// String conversion errors
    IntoString(IntoStringError),

    /// File path already exists
    ExistingFile(String),

    /// Error unlocking a mutex
    UnlockError,
}

/// Error raised when the user requests invalid indexes for data
#[derive(Debug, PartialEq, Eq)]
pub struct IndexError {
    /// Error message
    pub message: String,

    /// The range requested by the user
    pub given: Range<usize>,
}

/// Handy error type for use internally
pub type Result<T> = ::std::result::Result<T, Error>;

impl ::std::convert::From<FitsError> for Error {
    fn from(error: FitsError) -> Self {
        Error::Fits(error)
    }
}

impl ::std::convert::From<IndexError> for Error {
    fn from(error: IndexError) -> Self {
        Error::Index(error)
    }
}

impl<'a> ::std::convert::From<&'a str> for Error {
    fn from(error: &'a str) -> Self {
        Error::Message(error.to_string())
    }
}

impl ::std::convert::From<NulError> for Error {
    fn from(error: NulError) -> Self {
        Error::Null(error)
    }
}

impl ::std::convert::From<FromUtf8Error> for Error {
    fn from(error: FromUtf8Error) -> Self {
        Error::Utf8(error.utf8_error())
    }
}

impl ::std::convert::From<Utf8Error> for Error {
    fn from(error: Utf8Error) -> Self {
        Error::Utf8(error)
    }
}

impl ::std::convert::From<Box<::std::error::Error>> for Error {
    fn from(error: Box<::std::error::Error>) -> Self {
        let description = error.description();
        let message = match error.source() {
            Some(msg) => format!("Error: {} caused by {}", description, msg),
            None => format!("Error: {}", description),
        };
        Error::Message(message)
    }
}

impl ::std::convert::From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

impl ::std::convert::From<IntoStringError> for Error {
    fn from(e: IntoStringError) -> Self {
        Error::IntoString(e)
    }
}

use fitsfile::FitsFile;
type PoisonError<'a> = sync::PoisonError<sync::MutexGuard<'a, FitsFile>>;

impl<'a> ::std::convert::From<PoisonError<'a>> for Error {
    fn from(_e: PoisonError) -> Self {
        Error::UnlockError
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        match *self {
            Error::Fits(ref e) => write!(f, "Fits error: {:?}", e),
            Error::Message(ref s) => write!(f, "Error: {}", s),
            Error::Null(ref e) => e.fmt(f),
            Error::Utf8(ref e) => e.fmt(f),
            Error::Index(ref e) => write!(f, "Error: {:?}", e),
            Error::Io(ref e) => e.fmt(f),
            Error::IntoString(ref e) => e.fmt(f),
            Error::ExistingFile(ref filename) => write!(f, "File {} already exists", filename),
            Error::UnlockError => write!(f, "Invalid concurrent access to fits file"),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        "fitsio error"
    }
}

/**
Error type

`cfitsio` passes errors through integer status codes. This struct wraps this and its associated
error message.
*/
#[derive(Debug, PartialEq, Eq)]
pub struct FitsError {
    /// `cfitsio` error code
    pub status: i32,
    /// `cfitsio` message for error code
    pub message: String,
}

/// Function for chaining result types
pub fn check_status(status: i32) -> Result<()> {
    match status {
        0 => Ok(()),
        _ => Err(Error::Fits(FitsError {
            status,
            message: status_to_string(status)?.expect("guaranteed to be Some"),
        })),
    }
}

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

    #[test]
    fn test_check_status_ok() {
        assert!(check_status(0).is_ok());
    }

    #[test]
    fn test_check_status_ok_with_value() {
        assert_eq!(check_status(0).map(|_| 10i32).unwrap(), 10i32);
    }

    #[test]
    fn test_check_status_with_err() {
        assert!(check_status(105).map(|_| 10i32).is_err());
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate log;
#[macro_use] extern crate p_macro;
#[macro_use] extern crate maplit;
#[macro_use] extern crate lazy_static;
extern crate libc;
#[macro_use] extern crate libpact_v1_matching;
extern crate rustc_serialize;
extern crate env_logger;
#[macro_use] extern crate hyper;
extern crate uuid;

use libc::{c_char, int32_t};
use std::ffi::CStr;
use std::ffi::CString;
use std::mem;
use std::str;
use libpact_v1_matching::models::{Pact, Interaction, Request, Response, OptionalBody};
use libpact_v1_matching::models::parse_query_string;
use libpact_v1_matching::Mismatch;
use rustc_serialize::json::{self, Json, ToJson};
use std::collections::{BTreeMap, HashMap};
use std::thread;
use std::sync::Mutex;
use std::sync::mpsc::channel;
use std::io::{Read, Write};
use hyper::server::Server;
use hyper::status::StatusCode;
use hyper::header::{Headers, ContentType, AccessControlAllowOrigin, ContentLength};
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use hyper::uri::RequestUri;
use uuid::Uuid;

#[derive(Debug, Clone, PartialEq)]
pub enum MatchResult {
    RequestMatch(Response),
    RequestMismatch(Vec<(Interaction, Vec<Mismatch>)>),
    RequestNotFound(Request)
}

impl MatchResult {
    pub fn match_key(&self) -> String {
        match self {
            &MatchResult::RequestMatch(_) => s!("Request-Matched"),
            &MatchResult::RequestMismatch(_) => s!("Request-Mismatch"),
            &MatchResult::RequestNotFound(_) => s!("Unexpected-Request")
        }
    }

    pub fn matched(&self) -> bool {
        match self {
            &MatchResult::RequestMatch(_) => true,
            _ => false
        }
    }

    pub fn to_json(&self) -> Json {
        match self {
            &MatchResult::RequestMatch(_) => Json::Object(btreemap!{ s!("type") => s!("request-match").to_json() }),
            &MatchResult::RequestMismatch(ref mismatches) => mismatches_to_json(mismatches),
            &MatchResult::RequestNotFound(ref req) => Json::Object(btreemap!{
                s!("type") => s!("request-not-found").to_json(),
                s!("method") => req.method.to_json(),
                s!("path") => req.path.to_json()
            })
        }
    }
}

fn mismatches_to_json(mismatches: &Vec<(Interaction, Vec<Mismatch>)>) -> Json {
    let req = &mismatches[0].0.request;
    let mut array = vec![];
    for ref mismatch_ref in mismatches {
        let mut map = btreemap!{
            s!("type") => s!("request-mismatch").to_json(),
            s!("method") => mismatch_ref.0.request.method.to_json(),
            s!("path") => mismatch_ref.0.request.path.to_json()
        };
        let mut mismatch_array = vec![];
        for ms in &mismatch_ref.1 {
            mismatch_array.push(ms.to_json());
        }
        map.insert(s!("mismatches"), Json::Array(mismatch_array));
        array.push(Json::Object(map));
    }
    Json::Object(btreemap!{
        s!("type") => s!("request-mismatch").to_json(),
        s!("method") => req.method.to_json(),
        s!("path") => req.path.to_json(),
        s!("mismatches") => Json::Array(array)
    })
}

#[derive(Debug, Clone, PartialEq)]
pub struct MockServer {
    pub id: String,
    pub port: i32,
    pub matches: Vec<MatchResult>
}

impl MockServer {
    pub fn new(id: String) -> MockServer {
        MockServer { id: id.clone(), port: -1, matches: vec![] }
    }

    pub fn port(&mut self, port: i32) {
        self.port = port;
    }
}

lazy_static! {
    static ref MOCK_SERVERS: Mutex<BTreeMap<String, Box<MockServer>>> = Mutex::new(BTreeMap::new());
}

fn match_request(req: &Request, interactions: &Vec<Interaction>) -> MatchResult {
    let list = interactions.clone();
    let list: Vec<Interaction> = list.iter().filter(|i| {
        i.request.method == req.method && i.request.path == req.path
    }).map(|i| i.clone() ).collect();
    if list.is_empty() {
        MatchResult::RequestNotFound(req.clone())
    } else {
        let matches: Vec<(Interaction, Vec<Mismatch>)> = list.iter().map(|i| {
            let mismatches = libpact_v1_matching::match_request(i.request.clone(), req.clone());
            (i.clone(), mismatches)
        }).collect();
        match matches.iter().find(|i| i.1.is_empty()) {
            Some(i) => MatchResult::RequestMatch(i.clone().0.response),
            None => MatchResult::RequestMismatch(matches.clone())
        }
    }
}

fn extract_path(uri: &RequestUri) -> String {
    match uri {
        &RequestUri::AbsolutePath(ref s) => s!(s.splitn(2, "?").next().unwrap_or("/")),
        &RequestUri::AbsoluteUri(ref url) => url.path().unwrap_or(&[s!("")]).join("/"),
        _ => uri.to_string()
    }
}

fn extract_query_string(uri: &RequestUri) -> Option<HashMap<String, Vec<String>>> {
    match uri {
        &RequestUri::AbsolutePath(ref s) => {
            if s.contains("?") {
                match s.splitn(2, "?").last() {
                    Some(q) => parse_query_string(&s!(q)),
                    None => None
                }
            } else {
                None
            }
        },
        &RequestUri::AbsoluteUri(ref url) => match url.query {
            Some(ref q) => parse_query_string(q),
            None => None
        },
        _ => None
    }
}

fn extract_headers(headers: &Headers) -> Option<HashMap<String, String>> {
    if headers.len() > 0 {
        Some(headers.iter().map(|h| (s!(h.name()), h.value_string()) ).collect())
    } else {
        None
    }
}

fn extract_body(req: &mut hyper::server::Request) -> OptionalBody {
    let mut buffer = String::new();
    match req.read_to_string(&mut buffer) {
        Ok(size) => if size > 0 {
                OptionalBody::Present(buffer)
            } else {
                OptionalBody::Empty
            },
        Err(err) => {
            warn!("Failed to read request body: {}", err);
            OptionalBody::Empty
        }
    }
}

fn hyper_request_to_pact_request(req: &mut hyper::server::Request) -> Request {
    Request {
        method: req.method.to_string(),
        path: extract_path(&req.uri),
        query: extract_query_string(&req.uri),
        headers: extract_headers(&req.headers),
        body: extract_body(req),
        matching_rules: None
    }
}

fn error_body(req: &Request, error: &String) -> String {
    let body = hashmap!{ "error" => format!("{} : {:?}", error, req) };
    let json = json::encode(&body).unwrap();
    json.clone()
}

fn insert_new_mock_server(id: &String) {
    MOCK_SERVERS.lock().unwrap().insert(id.clone(), Box::new(MockServer::new(id.clone())));
}

fn update_mock_server(id: &String, f: &Fn(&mut MockServer) -> ()) -> bool {
    match MOCK_SERVERS.lock().unwrap().get_mut(id) {
        Some(mock_server) => { f(mock_server); true },
        _ => false
    }
}

fn record_result(id: &String, match_result: &MatchResult) {
    update_mock_server(id, &|mock_server: &mut MockServer| {
        mock_server.matches.push(match_result.clone());
    });
}

fn start_mock_server(id: String, pact: Pact) -> Result<i32, String> {
    insert_new_mock_server(&id);
    let (out_tx, out_rx) = channel();
    let (in_tx, in_rx) = channel();
    in_tx.send((id.clone(), pact)).unwrap();
    thread::spawn(move || {
        let (mock_server_id, pact) = in_rx.recv().unwrap();
        let server = Server::http("0.0.0.0:0").unwrap();
        let server_result = server.handle(move |mut req: hyper::server::Request, mut res: hyper::server::Response| {
            let req = hyper_request_to_pact_request(&mut req);
            debug!("Received request {:?}", req);
            let match_result = match_request(&req, &pact.interactions);
            record_result(&mock_server_id, &match_result);
            match match_result {
                MatchResult::RequestMatch(ref response) => {
                    debug!("Request matched, sending response {:?}", response);
                    *res.status_mut() = StatusCode::from_u16(response.status);
                    match response.headers {
                        Some(ref headers) => {
                            for (k, v) in headers.clone() {
                                res.headers_mut().set_raw(k, vec![v.into_bytes()]);
                            }
                        },
                        None => ()
                    }
                    match response.body {
                        OptionalBody::Present(ref body) => {
                            res.send(body.as_bytes()).unwrap();
                        },
                        _ => ()
                    }
                },
                _ => {
                    *res.status_mut() = StatusCode::InternalServerError;
                    res.headers_mut().set(
                        ContentType(Mime(TopLevel::Application, SubLevel::Json,
                                         vec![(Attr::Charset, Value::Utf8)]))
                    );
                    res.headers_mut().set(AccessControlAllowOrigin::Any);
                    res.headers_mut().set_raw("X-Pact", vec![match_result.match_key().as_bytes().to_vec()]);
                    let body = error_body(&req, &match_result.match_key());
                    res.headers_mut().set(ContentLength(body.as_bytes().len() as u64));
                    let mut res = res.start().unwrap();
                    res.write_all(body.as_bytes()).unwrap();
                }
            }
        });

        match server_result {
            Ok(server) => {
                let port = server.socket.port() as i32;
                info!("Mock Provider Server started on port {}", port);
                out_tx.send(Ok(port)).unwrap();
            },
            Err(e) => {
                error!("Could not start server: {}", e);
                out_tx.send(Err(format!("Could not start server: {}", e))).unwrap();
            }
        }
    });

    match out_rx.recv().unwrap() {
        Err(err) => Err(err),
        Ok(port) => {
            update_mock_server(&id, &|mock_server| mock_server.port(port) );
            Ok(port)
        }
    }
}

fn lookup_mock_server<R>(mock_server_port: i32, f: &Fn(&mut MockServer) -> R) -> Option<R> {
    let mut map = MOCK_SERVERS.lock().unwrap();
    match map.iter_mut().find(|ms| ms.1.port == mock_server_port ) {
        Some(mock_server) => Some(f(&mut *mock_server.1)),
        None => None
    }
}

#[no_mangle]
pub extern fn create_mock_server(pact_str: *const c_char) -> int32_t {
    env_logger::init().unwrap();

    let c_str = unsafe {
        if pact_str.is_null() {
            error!("Got a null pointer instead of pact json");
            return -1;
        }
        CStr::from_ptr(pact_str)
    };

    let pact_json = str::from_utf8(c_str.to_bytes()).unwrap();
    let result = Json::from_str(pact_json);
    match result {
        Ok(pact_json) => {
            let pact = Pact::from_json(&pact_json);
            match start_mock_server(Uuid::new_v4().to_string(), pact) {
                Ok(mock_server) => mock_server as i32,
                Err(msg) => {
                    error!("Could not start mock server: {}", msg);
                    -3
                }
            }
        },
        Err(err) => {
            error!("Could not parse pact json: {}", err);
            -2
        }
    }
}

#[no_mangle]
pub extern fn mock_server_matched(mock_server_port: int32_t) -> bool {
    lookup_mock_server(mock_server_port, &|mock_server| {
        !mock_server.matches.iter().any(|mismatch| !mismatch.matched())
    }).unwrap_or(false)
}

#[no_mangle]
pub extern fn mock_server_mismatches(mock_server_port: int32_t) -> *mut c_char {
    let mismatches = lookup_mock_server(mock_server_port, &|mock_server| {
        mock_server.matches.iter()
            .filter(|mismatch| !mismatch.matched())
            .map(|mismatch| mismatch.to_json() )
            .collect::<Vec<Json>>()
    });
    let json = match mismatches {
        Some(array) => Json::Array(array),
        None => Json::Null
    };
    let s = CString::new(json.to_string()).unwrap();
    let p = s.as_ptr();
    mem::forget(s);
    p as *mut _
}

#[no_mangle]
pub extern fn cleanup_mock_server(mock_server_port: int32_t) -> bool {
    lookup_mock_server(mock_server_port, &|mock_server| {
        true
    }).unwrap_or(false)
}
<commit_msg>implemented mock server cleanup<commit_after>#[macro_use] extern crate log;
#[macro_use] extern crate p_macro;
#[macro_use] extern crate maplit;
#[macro_use] extern crate lazy_static;
extern crate libc;
#[macro_use] extern crate libpact_v1_matching;
extern crate rustc_serialize;
extern crate env_logger;
#[macro_use] extern crate hyper;
extern crate uuid;

use libc::{c_char, int32_t};
use std::ffi::CStr;
use std::ffi::CString;
use std::str;
use libpact_v1_matching::models::{Pact, Interaction, Request, Response, OptionalBody};
use libpact_v1_matching::models::parse_query_string;
use libpact_v1_matching::Mismatch;
use rustc_serialize::json::{self, Json, ToJson};
use std::collections::{BTreeMap, HashMap};
use std::thread;
use std::sync::Mutex;
use std::sync::mpsc::channel;
use std::io::{Read, Write};
use hyper::server::{Server, Listening};
use hyper::status::StatusCode;
use hyper::header::{Headers, ContentType, AccessControlAllowOrigin, ContentLength};
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use hyper::uri::RequestUri;
use uuid::Uuid;

#[derive(Debug, Clone, PartialEq)]
pub enum MatchResult {
    RequestMatch(Response),
    RequestMismatch(Vec<(Interaction, Vec<Mismatch>)>),
    RequestNotFound(Request)
}

impl MatchResult {
    pub fn match_key(&self) -> String {
        match self {
            &MatchResult::RequestMatch(_) => s!("Request-Matched"),
            &MatchResult::RequestMismatch(_) => s!("Request-Mismatch"),
            &MatchResult::RequestNotFound(_) => s!("Unexpected-Request")
        }
    }

    pub fn matched(&self) -> bool {
        match self {
            &MatchResult::RequestMatch(_) => true,
            _ => false
        }
    }

    pub fn to_json(&self) -> Json {
        match self {
            &MatchResult::RequestMatch(_) => Json::Object(btreemap!{ s!("type") => s!("request-match").to_json() }),
            &MatchResult::RequestMismatch(ref mismatches) => mismatches_to_json(mismatches),
            &MatchResult::RequestNotFound(ref req) => Json::Object(btreemap!{
                s!("type") => s!("request-not-found").to_json(),
                s!("method") => req.method.to_json(),
                s!("path") => req.path.to_json()
            })
        }
    }
}

fn mismatches_to_json(mismatches: &Vec<(Interaction, Vec<Mismatch>)>) -> Json {
    let req = &mismatches[0].0.request;
    let mut array = vec![];
    for ref mismatch_ref in mismatches {
        let mut map = btreemap!{
            s!("type") => s!("request-mismatch").to_json(),
            s!("method") => mismatch_ref.0.request.method.to_json(),
            s!("path") => mismatch_ref.0.request.path.to_json()
        };
        let mut mismatch_array = vec![];
        for ms in &mismatch_ref.1 {
            mismatch_array.push(ms.to_json());
        }
        map.insert(s!("mismatches"), Json::Array(mismatch_array));
        array.push(Json::Object(map));
    }
    Json::Object(btreemap!{
        s!("type") => s!("request-mismatch").to_json(),
        s!("method") => req.method.to_json(),
        s!("path") => req.path.to_json(),
        s!("mismatches") => Json::Array(array)
    })
}

pub struct MockServer {
    pub id: String,
    pub port: i32,
    pub server: u64,
    pub matches: Vec<MatchResult>,
    pub resources: Vec<CString>
}

impl MockServer {
    pub fn new(id: String) -> MockServer {
        MockServer { id: id.clone(), port: -1, server: 0, matches: vec![], resources: vec![] }
    }

    pub fn port(&mut self, port: i32) {
        self.port = port;
    }

    pub fn server(&mut self, server: &Listening) {
        let p = server as *const Listening;
        self.server = p as u64;
    }
}

impl PartialEq for MockServer {
    fn eq(&self, other: &MockServer) -> bool {
        self.id == other.id
    }
}

lazy_static! {
    static ref MOCK_SERVERS: Mutex<BTreeMap<String, Box<MockServer>>> = Mutex::new(BTreeMap::new());
}

fn match_request(req: &Request, interactions: &Vec<Interaction>) -> MatchResult {
    let list = interactions.clone();
    let list: Vec<Interaction> = list.iter().filter(|i| {
        i.request.method == req.method && i.request.path == req.path
    }).map(|i| i.clone() ).collect();
    if list.is_empty() {
        MatchResult::RequestNotFound(req.clone())
    } else {
        let matches: Vec<(Interaction, Vec<Mismatch>)> = list.iter().map(|i| {
            let mismatches = libpact_v1_matching::match_request(i.request.clone(), req.clone());
            (i.clone(), mismatches)
        }).collect();
        match matches.iter().find(|i| i.1.is_empty()) {
            Some(i) => MatchResult::RequestMatch(i.clone().0.response),
            None => MatchResult::RequestMismatch(matches.clone())
        }
    }
}

fn extract_path(uri: &RequestUri) -> String {
    match uri {
        &RequestUri::AbsolutePath(ref s) => s!(s.splitn(2, "?").next().unwrap_or("/")),
        &RequestUri::AbsoluteUri(ref url) => url.path().unwrap_or(&[s!("")]).join("/"),
        _ => uri.to_string()
    }
}

fn extract_query_string(uri: &RequestUri) -> Option<HashMap<String, Vec<String>>> {
    match uri {
        &RequestUri::AbsolutePath(ref s) => {
            if s.contains("?") {
                match s.splitn(2, "?").last() {
                    Some(q) => parse_query_string(&s!(q)),
                    None => None
                }
            } else {
                None
            }
        },
        &RequestUri::AbsoluteUri(ref url) => match url.query {
            Some(ref q) => parse_query_string(q),
            None => None
        },
        _ => None
    }
}

fn extract_headers(headers: &Headers) -> Option<HashMap<String, String>> {
    if headers.len() > 0 {
        Some(headers.iter().map(|h| (s!(h.name()), h.value_string()) ).collect())
    } else {
        None
    }
}

fn extract_body(req: &mut hyper::server::Request) -> OptionalBody {
    let mut buffer = String::new();
    match req.read_to_string(&mut buffer) {
        Ok(size) => if size > 0 {
                OptionalBody::Present(buffer)
            } else {
                OptionalBody::Empty
            },
        Err(err) => {
            warn!("Failed to read request body: {}", err);
            OptionalBody::Empty
        }
    }
}

fn hyper_request_to_pact_request(req: &mut hyper::server::Request) -> Request {
    Request {
        method: req.method.to_string(),
        path: extract_path(&req.uri),
        query: extract_query_string(&req.uri),
        headers: extract_headers(&req.headers),
        body: extract_body(req),
        matching_rules: None
    }
}

fn error_body(req: &Request, error: &String) -> String {
    let body = hashmap!{ "error" => format!("{} : {:?}", error, req) };
    let json = json::encode(&body).unwrap();
    json.clone()
}

fn insert_new_mock_server(id: &String) {
    MOCK_SERVERS.lock().unwrap().insert(id.clone(), Box::new(MockServer::new(id.clone())));
}

fn update_mock_server(id: &String, f: &Fn(&mut MockServer) -> ()) -> bool {
    match MOCK_SERVERS.lock().unwrap().get_mut(id) {
        Some(mock_server) => { f(mock_server); true },
        _ => false
    }
}

fn record_result(id: &String, match_result: &MatchResult) {
    update_mock_server(id, &|mock_server: &mut MockServer| {
        mock_server.matches.push(match_result.clone());
    });
}

fn start_mock_server(id: String, pact: Pact) -> Result<i32, String> {
    insert_new_mock_server(&id);
    let (out_tx, out_rx) = channel();
    let (in_tx, in_rx) = channel();
    in_tx.send((id.clone(), pact)).unwrap();
    thread::spawn(move || {
        let (mock_server_id, pact) = in_rx.recv().unwrap();
        let server = Server::http("0.0.0.0:0").unwrap();
        let server_result = server.handle(move |mut req: hyper::server::Request, mut res: hyper::server::Response| {
            let req = hyper_request_to_pact_request(&mut req);
            debug!("Received request {:?}", req);
            let match_result = match_request(&req, &pact.interactions);
            record_result(&mock_server_id, &match_result);
            match match_result {
                MatchResult::RequestMatch(ref response) => {
                    debug!("Request matched, sending response {:?}", response);
                    *res.status_mut() = StatusCode::from_u16(response.status);
                    match response.headers {
                        Some(ref headers) => {
                            for (k, v) in headers.clone() {
                                res.headers_mut().set_raw(k, vec![v.into_bytes()]);
                            }
                        },
                        None => ()
                    }
                    match response.body {
                        OptionalBody::Present(ref body) => {
                            res.send(body.as_bytes()).unwrap();
                        },
                        _ => ()
                    }
                },
                _ => {
                    *res.status_mut() = StatusCode::InternalServerError;
                    res.headers_mut().set(
                        ContentType(Mime(TopLevel::Application, SubLevel::Json,
                                         vec![(Attr::Charset, Value::Utf8)]))
                    );
                    res.headers_mut().set(AccessControlAllowOrigin::Any);
                    res.headers_mut().set_raw("X-Pact", vec![match_result.match_key().as_bytes().to_vec()]);
                    let body = error_body(&req, &match_result.match_key());
                    res.headers_mut().set(ContentLength(body.as_bytes().len() as u64));
                    let mut res = res.start().unwrap();
                    res.write_all(body.as_bytes()).unwrap();
                }
            }
        });

        match server_result {
            Ok(ref server) => {
                let port = server.socket.port() as i32;
                info!("Mock Provider Server started on port {}", port);
                update_mock_server(&id, &|mock_server| {
                    mock_server.port(port);
                    mock_server.server(server);
                });
                out_tx.send(Ok(port)).unwrap();
            },
            Err(e) => {
                error!("Could not start server: {}", e);
                out_tx.send(Err(format!("Could not start server: {}", e))).unwrap();
            }
        }
    });

    out_rx.recv().unwrap()
}

fn lookup_mock_server<R>(mock_server_port: i32, f: &Fn(&mut MockServer) -> R) -> Option<R> {
    let mut map = MOCK_SERVERS.lock().unwrap();
    match map.iter_mut().find(|ms| ms.1.port == mock_server_port ) {
        Some(mock_server) => Some(f(&mut *mock_server.1)),
        None => None
    }
}

#[no_mangle]
pub extern fn create_mock_server(pact_str: *const c_char) -> int32_t {
    env_logger::init().unwrap();

    let c_str = unsafe {
        if pact_str.is_null() {
            error!("Got a null pointer instead of pact json");
            return -1;
        }
        CStr::from_ptr(pact_str)
    };

    let pact_json = str::from_utf8(c_str.to_bytes()).unwrap();
    let result = Json::from_str(pact_json);
    match result {
        Ok(pact_json) => {
            let pact = Pact::from_json(&pact_json);
            match start_mock_server(Uuid::new_v4().to_string(), pact) {
                Ok(mock_server) => mock_server as i32,
                Err(msg) => {
                    error!("Could not start mock server: {}", msg);
                    -3
                }
            }
        },
        Err(err) => {
            error!("Could not parse pact json: {}", err);
            -2
        }
    }
}

#[no_mangle]
pub extern fn mock_server_matched(mock_server_port: int32_t) -> bool {
    lookup_mock_server(mock_server_port, &|mock_server| {
        !mock_server.matches.iter().any(|mismatch| !mismatch.matched())
    }).unwrap_or(false)
}

#[no_mangle]
pub extern fn mock_server_mismatches(mock_server_port: int32_t) -> *mut c_char {
    let result = lookup_mock_server(mock_server_port, &|mock_server| {
        let mismatches = mock_server.matches.iter()
            .filter(|mismatch| !mismatch.matched())
            .map(|mismatch| mismatch.to_json() )
            .collect::<Vec<Json>>();
        let json = Json::Array(mismatches);
        let s = CString::new(json.to_string()).unwrap();
        let p = s.as_ptr();
        mock_server.resources.push(s);
        p
    });
    match result {
        Some(p) => p as *mut _,
        None => 0 as *mut _
    }
}

#[no_mangle]
pub extern fn cleanup_mock_server(mock_server_port: int32_t) -> bool {
    let id_result = lookup_mock_server(mock_server_port, &|mock_server| {
        mock_server.resources.clear();
        if mock_server.server > 0 {
            let server_raw = mock_server.server as *mut Listening;
            let mut server_ref = unsafe { &mut *server_raw };
            server_ref.close().unwrap();
        }
        mock_server.id.clone()
    });

    match id_result {
        Some(ref id) => {
            MOCK_SERVERS.lock().unwrap().remove(id);
            true
        },
        None => false
    }
}
<|endoftext|>


<commit_before>/*
	Autor: Gustavo Michels de Camargo

	Projeto: Algoritmo estrural de um Grafo

*/

use std::{collections::HashMap};

// Matriz de Vector usada ara construir o Grafo.
type MatrizGrafo = Vec<Vec<isize>>;

// O dicionario serve para podermos dar entrada a qualquer String e ter como abstrair suas posições dentro.
// da matriz numerica, isso serve apenas para fins de uso, não requerer transcrever um Nodo com X para valor numerico.
#[derive(PartialEq, Eq, Clone, Debug)]
struct Grafo {
	matriz: MatrizGrafo,
	dicionario: HashMap<String, usize>,
	bicondicional: bool
}

trait Projeto {
	// Geral
	fn new(tamanho: usize, tipo: &str) -> Grafo;

	// Funcçoes envolvendo o dicionario - Usuario
	fn usr_pegar_indice(&self, chave: String) -> usize;
	fn usr_pegar_chave(&self, indice: usize) -> String;

	// Usuario
	fn usr_adicionar_conexao(&mut self, a: String, b: String, valor: isize);
	fn usr_remover_conexao(&mut self, a: String, b: String);
	fn usr_numero_conexoes(&self, no: String) -> usize;
	fn usr_verificar_se_existe_conexao(&self, a: String, b: String) -> bool;
	fn usr_conexoes(&self, a: String) -> Vec<String>;

	// Maquina / uso para os Algoritmos
	fn adicionar_conexao(&mut self, a: usize, b: usize, valor: isize);
	fn remover_conexao(&mut self, a: usize, b: usize);
	fn numero_conexoes(&self, no: usize) -> usize;
	fn verificar_se_existe_conexao(&self, a: usize, b: usize) -> bool;
	fn conexoes(&self, a: usize) -> Vec<usize>;

	// Algoritmos que atuam sobre Grafos
}

// Este é a implementação da "Classe" de um grafo.
impl Projeto for Grafo {
	// Tamanho: Numero Maximo de Vertices que a matriz ppode usar de 0 até tamanho.
	// Em notação matematica relativa a limites: [0, tamanho).
	// Toda função que começa com 'usr_'(usr = usuario) é a versão da função que deve ser usada para interagir diretamente com o usuario.
	// As funções de mesmo nome mas sem 'usr_' deve ser usada apenas dentro dos algoritmos, como o Dijkstra para menor caminho entre dois nos.
	// Fiz assim para otimizar processamento e descartar necessidade de acessar e
	// consultaro dicionario o tempo todo quando se apenas como Objetivo encontrar um menor caminho com Dijkstra por exemplo.

	// Apenas essa função foge a regra por ser universal
	fn new(tamanho: usize, tipo: &str) -> Grafo {
		Grafo {
			matriz: vec![vec![-1; tamanho]; tamanho],
			dicionario: HashMap::new(),
			bicondicional: match tipo  {
				"->" => false, // Condicional
				"<->" | _ => true // Bicondicional
			}
		}
	}

	// ---- Funções para uso direto do usuario ----

	// Retorna o indice da matriz relacionada a chave
	fn usr_pegar_indice(&self, chave: String) -> usize {
		if self.dicionario.contains_key(&chave) {
			return (&self.dicionario.get(&chave)).unwrap().clone();
		}

		return 0;
	}

	// Retorna a chave do dicionario relacionada ao valor do indice da matriz do grafo
	fn usr_pegar_chave(&self, indice: usize) -> String {
		for (key, value) in self.dicionario.iter() {
			if *value == indice {
				return (*key).clone();
			}
		}

		return "".to_string();
	}

	// Conecta Dois vertices
	fn usr_adicionar_conexao(&mut self, a: String, b: String, valor: isize) {
		if !self.dicionario.contains_key(&a){
			let num: usize = self.dicionario.len();
			self.dicionario.insert(a.to_owned(), num);
		}

		if !self.dicionario.contains_key(&b){
			let num: usize = self.dicionario.len();
			self.dicionario.insert(b.to_owned(), num);
		}

		let (valor_a, valor_b): (usize, usize) = (self.usr_pegar_indice(a), self.usr_pegar_indice(b));

		self.matriz[valor_a][valor_b] = valor;

		if self.bicondicional {
			self.matriz[valor_b][valor_a] = valor;
		}

	}

	fn usr_remover_conexao(&mut self, a: String, b: String) {
		let (valor_a, valor_b): (usize, usize) = (self.usr_pegar_indice(a), self.usr_pegar_indice(b));

		self.matriz[valor_a][valor_b]  = -1;
		self.matriz[valor_b][valor_a]  = -1;
	}

	// Retorba o numero de vertices na qual ele se conecta
	fn usr_numero_conexoes(&self, no: String) -> usize {
		self.matriz[self.usr_pegar_indice(no)].iter()
						.filter(|x| **x >= 0)
						.collect::<Vec<&isize>>()
						.len() as usize | 0
	}

	// Verifica se dois nos estão conectados
	fn usr_verificar_se_existe_conexao(&self, a: String, b: String) -> bool {
		self.matriz[self.usr_pegar_indice(a)][self.usr_pegar_indice(b)]  >= 0
	}

	fn usr_conexoes(&self, a: String) -> Vec<String> {
		let mut result: Vec<String> = Vec::new();
		let a_value: usize = self.usr_pegar_indice(a);

		for i in 0..self.matriz[a_value].len() {
			if a_value != i && self.matriz[a_value][i] > -1 {
				result.push(self.usr_pegar_chave(i));
			}
		}

		return result;
	}

	// ---- Funções para uso direto dos algoritmos (tem melhor perfomance) ----

	// Retorna um array dos indice de todos os nos na qual o no 'a' se conecta
	// Esera usar esta função apenas para usos proprios dentro do Grafo, como em algoritmos tipo dijkstra
	// Conecta Dois vertices
	fn adicionar_conexao(&mut self, a: usize, b: usize, valor: isize) {
		self.matriz[a][b] = valor;

		if self.bicondicional {
			self.matriz[b][a] = valor;
		}
	}

	fn remover_conexao(&mut self, a: usize, b: usize) {
		self.matriz[a][b]  = -1;
		self.matriz[b][a]  = -1;
	}

	// Retorba o numero de vertices na qual ele se conecta
	fn numero_conexoes(&self, no: usize) -> usize {
		self.matriz[no].iter()
						.filter(|x| **x >= 0)
						.collect::<Vec<&isize>>()
						.len() as usize | 0
	}

	fn verificar_se_existe_conexao(&self, a: usize, b: usize) -> bool {
		self.matriz[a][b]  >= 0
	}

	fn conexoes(&self, a: usize) -> Vec<usize> {
		let mut result: Vec<usize> = Vec::new();

		for i in 0..self.matriz[a].len() {
			if a != i && self.matriz[a][i] > -1 {
				result.push(i);
			}
		}
		return result;
	}

	// ---- Funções dos algoritmos ----

}

// Main
fn main() {
	// Grafo com no maximo mil vertices
	 // "->" =  Grafo condicional, "<->" = Grafo Bicondicional
	let mut grafo: Grafo = Grafo::new(1000, "->");

	grafo.usr_adicionar_conexao(0.to_string(), 1.to_string(), 1);
	grafo.usr_adicionar_conexao(1.to_string(), 2.to_string(), 1);
	grafo.usr_adicionar_conexao(2.to_string(), 3.to_string(), 1);
	grafo.usr_adicionar_conexao(3.to_string(), 0.to_string(), 1);

	println!("{:?}", grafo.conexoes(2));
}

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

	#[test]
	fn usr_numero_conexoes() {
		let mut grafo: Grafo = Grafo::new(1000, "->");

		for i in 1..1000 {
			grafo.usr_adicionar_conexao(0.to_string(), i.to_string(), 1);
		}

		assert_eq!(grafo.usr_numero_conexoes(0.to_string()), 999);
		assert_eq!(grafo.usr_numero_conexoes(0.to_string()), grafo.numero_conexoes(0));
	}

	#[test]
	fn numero_conexoes() {
		let mut grafo: Grafo = Grafo::new(1000, "<->");

		for i in 1..1000 {
			grafo.adicionar_conexao(0, i, 1);
		}

		assert_eq!(grafo.numero_conexoes(0), 999);
		assert_eq!(grafo.numero_conexoes(0), grafo.usr_numero_conexoes(0.to_string()));
	}
}
<commit_msg>Ajustando erros de portugues e retirando outras coisas pedidas<commit_after>/*
	Autor: Gustavo Michels de Camargo
	Projeto: Algoritmo estrural de um Grafo
*/

use std::{collections::HashMap};

// Matriz de Vector usada ara construir o Grafo.
type MatrizGrafo = Vec<Vec<isize>>;

// O dicionario serve para podermos dar entrada a qualquer String e ter como abstrair suas posições dentro.
// da matriz numerica, isso serve apenas para fins de uso, não requerer transcrever um Nodo com X para valor numerico.
#[derive(PartialEq, Eq, Clone, Debug)]
struct Grafo {
	matriz: MatrizGrafo,
	dicionario: HashMap<String, usize>,
	bicondicional: bool
}

trait Projeto {
	// Geral
	fn new(tamanho: usize, tipo: &str) -> Grafo;

	// Funções envolvendo o dicionario - Usuario
	fn usr_pegar_indice(&self, chave: String) -> usize;
	fn usr_pegar_chave(&self, indice: usize) -> String;

	// Usuario
	fn usr_adicionar_conexao(&mut self, a: String, b: String, valor: isize);
	fn usr_remover_conexao(&mut self, a: String, b: String);
	fn usr_numero_conexoes(&self, no: String) -> usize;
	fn usr_verificar_se_existe_conexao(&self, a: String, b: String) -> bool;
	fn usr_conexoes(&self, a: String) -> Vec<String>;

	// Maquina / uso para os Algoritmos
	fn adicionar_conexao(&mut self, a: usize, b: usize, valor: isize);
	fn remover_conexao(&mut self, a: usize, b: usize);
	fn numero_conexoes(&self, no: usize) -> usize;
	fn verificar_se_existe_conexao(&self, a: usize, b: usize) -> bool;
	fn conexoes(&self, a: usize) -> Vec<usize>;
}

// Este é a implementação da "Classe" de um grafo.
impl Projeto for Grafo {
	// Tamanho: Numero Maximo de Vertices que a matriz pode usar de 0 até tamanho.
	// Em notação matematica relativa a limites: [0, tamanho).
	// Toda função que começa com 'usr_'(usr = usuario) é a versão da função que deve ser usada para interagir diretamente com o usuario.
	// As funções de mesmo nome mas sem 'usr_' deve ser usada apenas dentro dos algoritmos, como o Dijkstra para menor caminho entre dois nos.
	// Fiz assim para otimizar processamento e descartar necessidade de acessar e
	// consultaro dicionario o tempo todo quando se apenas como Objetivo encontrar um menor caminho com Dijkstra por exemplo.

	// Apenas essa função foge a regra por ser universal
	fn new(tamanho: usize, tipo: &str) -> Grafo {
		Grafo {
			matriz: vec![vec![-1; tamanho]; tamanho],
			dicionario: HashMap::new(),
			bicondicional: match tipo  {
				"->" => false, // Condicional
				"<->" | _ => true // Bicondicional
			}
		}
	}

	// ---- Funções para uso direto do usuario ----

	// Retorna o indice da matriz relacionada a chave
	fn usr_pegar_indice(&self, chave: String) -> usize {
		if self.dicionario.contains_key(&chave) {
			return (&self.dicionario.get(&chave)).unwrap().clone();
		}

		return 0;
	}

	// Retorna a chave do dicionario relacionada ao valor do indice da matriz do grafo
	fn usr_pegar_chave(&self, indice: usize) -> String {
		for (key, value) in self.dicionario.iter() {
			if *value == indice {
				return (*key).clone();
			}
		}

		return "".to_string();
	}

	// Conecta Dois vertices
	fn usr_adicionar_conexao(&mut self, a: String, b: String, valor: isize) {
		if !self.dicionario.contains_key(&a){
			let num: usize = self.dicionario.len();
			self.dicionario.insert(a.to_owned(), num);
		}

		if !self.dicionario.contains_key(&b){
			let num: usize = self.dicionario.len();
			self.dicionario.insert(b.to_owned(), num);
		}

		let (valor_a, valor_b): (usize, usize) = (self.usr_pegar_indice(a), self.usr_pegar_indice(b));

		self.matriz[valor_a][valor_b] = valor;

		if self.bicondicional {
			self.matriz[valor_b][valor_a] = valor;
		}

	}

	fn usr_remover_conexao(&mut self, a: String, b: String) {
		let (valor_a, valor_b): (usize, usize) = (self.usr_pegar_indice(a), self.usr_pegar_indice(b));

		self.matriz[valor_a][valor_b]  = -1;
		self.matriz[valor_b][valor_a]  = -1;
	}

	// Retorba o numero de vertices na qual ele se conecta
	fn usr_numero_conexoes(&self, no: String) -> usize {
		self.matriz[self.usr_pegar_indice(no)].iter()
						.filter(|x| **x >= 0)
						.collect::<Vec<&isize>>()
						.len() as usize | 0
	}

	// Verifica se dois nos estão conectados
	fn usr_verificar_se_existe_conexao(&self, a: String, b: String) -> bool {
		self.matriz[self.usr_pegar_indice(a)][self.usr_pegar_indice(b)]  >= 0
	}

	fn usr_conexoes(&self, a: String) -> Vec<String> {
		let mut result: Vec<String> = Vec::new();
		let a_value: usize = self.usr_pegar_indice(a);

		for i in 0..self.matriz[a_value].len() {
			if a_value != i && self.matriz[a_value][i] > -1 {
				result.push(self.usr_pegar_chave(i));
			}
		}

		return result;
	}

	// ---- Funções para uso direto dos algoritmos (tem melhor perfomance) ----

	// Retorna um array dos indice de todos os nos na qual o no 'a' se conecta
	// Esera usar esta função apenas para usos proprios dentro do Grafo, como em algoritmos tipo dijkstra
	// Conecta Dois vertices
	fn adicionar_conexao(&mut self, a: usize, b: usize, valor: isize) {
		self.matriz[a][b] = valor;

		if self.bicondicional {
			self.matriz[b][a] = valor;
		}
	}

	fn remover_conexao(&mut self, a: usize, b: usize) {
		self.matriz[a][b]  = -1;
		self.matriz[b][a]  = -1;
	}

	// Retorba o numero de vertices na qual ele se conecta
	fn numero_conexoes(&self, no: usize) -> usize {
		self.matriz[no].iter()
						.filter(|x| **x >= 0)
						.collect::<Vec<&isize>>()
						.len() as usize | 0
	}

	fn verificar_se_existe_conexao(&self, a: usize, b: usize) -> bool {
		self.matriz[a][b]  >= 0
	}

	fn conexoes(&self, a: usize) -> Vec<usize> {
		let mut result: Vec<usize> = Vec::new();

		for i in 0..self.matriz[a].len() {
			if a != i && self.matriz[a][i] > -1 {
				result.push(i);
			}
		}
		return result;
	}

	// ---- Funções dos algoritmos ----

}

// Main
fn main() {
	// Grafo com no maximo mil vertices
	 // "->" =  Grafo condicional, "<->" = Grafo Bicondicional
	let mut grafo: Grafo = Grafo::new(1000, "->");

	grafo.usr_adicionar_conexao(0.to_string(), 1.to_string(), 1);
	grafo.usr_adicionar_conexao(1.to_string(), 2.to_string(), 1);
	grafo.usr_adicionar_conexao(2.to_string(), 3.to_string(), 1);
	grafo.usr_adicionar_conexao(3.to_string(), 0.to_string(), 1);

	println!("{:?}", grafo.conexoes(2));
}

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

	#[test]
	fn usr_numero_conexoes() {
		let mut grafo: Grafo = Grafo::new(1000, "->");

		for i in 1..1000 {
			grafo.usr_adicionar_conexao(0.to_string(), i.to_string(), 1);
		}

		assert_eq!(grafo.usr_numero_conexoes(0.to_string()), 999);
		assert_eq!(grafo.usr_numero_conexoes(0.to_string()), grafo.numero_conexoes(0));
	}

	#[test]
	fn numero_conexoes() {
		let mut grafo: Grafo = Grafo::new(1000, "<->");

		for i in 1..1000 {
			grafo.adicionar_conexao(0, i, 1);
		}

		assert_eq!(grafo.numero_conexoes(0), 999);
		assert_eq!(grafo.numero_conexoes(0), grafo.usr_numero_conexoes(0.to_string()));
	}
}
<|endoftext|>


<commit_before>use crate::{
    config, db,
    models::Version,
    schema::{crates, readme_renderings, versions},
    uploaders::Uploader,
};
use std::{io::Read, path::Path, sync::Arc, thread};

use cargo_registry_markdown::text_to_html;
use chrono::{TimeZone, Utc};
use clap::Clap;
use diesel::{dsl::any, prelude::*};
use flate2::read::GzDecoder;
use reqwest::{blocking::Client, header};
use tar::{self, Archive};

const CACHE_CONTROL_README: &str = "public,max-age=604800";
const USER_AGENT: &str = "crates-admin";

#[derive(Clap, Debug)]
#[clap(
    name = "render-readmes",
    about = "Iterates over every crate versions ever uploaded and (re-)renders their \
        readme using the readme renderer from the cargo_registry crate.",
    after_help = "Warning: this can take a lot of time."
)]
pub struct Opts {
    /// How many versions should be queried and processed at a time.
    #[clap(long, default_value = "25")]
    page_size: usize,

    /// Only rerender readmes that are older than this date.
    #[clap(long)]
    older_than: Option<String>,

    /// Only rerender readmes for the specified crate.
    #[clap(long = "crate")]
    crate_name: Option<String>,
}

pub fn run(opts: Opts) {
    let base_config = Arc::new(config::Base::from_environment());
    let conn = db::connect_now().unwrap();

    let start_time = Utc::now();

    let older_than = if let Some(ref time) = opts.older_than {
        Utc.datetime_from_str(time, "%Y-%m-%d %H:%M:%S")
            .expect("Could not parse --older-than argument as a time")
    } else {
        start_time
    };
    let older_than = older_than.naive_utc();

    println!("Start time:                   {}", start_time);
    println!("Rendering readmes older than: {}", older_than);

    let mut query = versions::table
        .inner_join(crates::table)
        .left_outer_join(readme_renderings::table)
        .filter(
            readme_renderings::rendered_at
                .lt(older_than)
                .or(readme_renderings::version_id.is_null()),
        )
        .select(versions::id)
        .into_boxed();

    if let Some(crate_name) = opts.crate_name {
        println!("Rendering readmes for {}", crate_name);
        query = query.filter(crates::name.eq(crate_name));
    }

    let version_ids: Vec<i32> = query.load(&conn).expect("error loading version ids");

    let total_versions = version_ids.len();
    println!("Rendering {} versions", total_versions);

    let page_size = opts.page_size;

    let total_pages = total_versions / page_size;
    let total_pages = if total_versions % page_size == 0 {
        total_pages
    } else {
        total_pages + 1
    };

    let client = Client::new();

    for (page_num, version_ids_chunk) in version_ids.chunks(page_size).enumerate() {
        println!(
            "= Page {} of {} ==================================",
            page_num + 1,
            total_pages
        );

        let versions: Vec<(Version, String)> = versions::table
            .inner_join(crates::table)
            .filter(versions::id.eq(any(version_ids_chunk)))
            .select((versions::all_columns, crates::name))
            .load(&conn)
            .expect("error loading versions");

        let mut tasks = Vec::with_capacity(page_size as usize);
        for (version, krate_name) in versions {
            Version::record_readme_rendering(version.id, &conn).unwrap_or_else(|_| {
                panic!(
                    "[{}-{}] Couldn't record rendering time",
                    krate_name, version.num
                )
            });
            let client = client.clone();
            let base_config = base_config.clone();
            let handle = thread::spawn(move || {
                println!("[{}-{}] Rendering README...", krate_name, version.num);
                let readme = get_readme(base_config.uploader(), &client, &version, &krate_name);
                if readme.is_none() {
                    return;
                }
                let readme = readme.unwrap();
                let content_length = readme.len() as u64;
                let content = std::io::Cursor::new(readme);
                let readme_path = format!("readmes/{0}/{0}-{1}.html", krate_name, version.num);
                let mut extra_headers = header::HeaderMap::new();
                extra_headers.insert(
                    header::CACHE_CONTROL,
                    header::HeaderValue::from_static(CACHE_CONTROL_README),
                );
                base_config
                    .uploader()
                    .upload(
                        &client,
                        &readme_path,
                        content,
                        content_length,
                        "text/html",
                        extra_headers,
                    )
                    .unwrap_or_else(|_| {
                        panic!(
                            "[{}-{}] Couldn't upload file to S3",
                            krate_name, version.num
                        )
                    });
            });
            tasks.push(handle);
        }
        for handle in tasks {
            if let Err(err) = handle.join() {
                println!("Thread panicked: {:?}", err);
            }
        }
    }
}

/// Renders the readme of an uploaded crate version.
fn get_readme(
    uploader: &Uploader,
    client: &Client,
    version: &Version,
    krate_name: &str,
) -> Option<String> {
    let location = uploader.crate_location(krate_name, &version.num.to_string());

    let location = match uploader {
        Uploader::S3 { .. } => location,
        Uploader::Local => format!("http://localhost:8888/{}", location),
    };

    let mut extra_headers = header::HeaderMap::new();
    extra_headers.insert(
        header::USER_AGENT,
        header::HeaderValue::from_static(USER_AGENT),
    );
    let response = match client.get(&location).headers(extra_headers).send() {
        Ok(r) => r,
        Err(err) => {
            println!(
                "[{}-{}] Unable to fetch crate: {}",
                krate_name, version.num, err
            );
            return None;
        }
    };

    if !response.status().is_success() {
        println!(
            "[{}-{}] Failed to get a 200 response: {}",
            krate_name,
            version.num,
            response.text().unwrap()
        );
        return None;
    }

    let reader = GzDecoder::new(response);
    let mut archive = Archive::new(reader);
    let mut entries = archive.entries().unwrap_or_else(|_| {
        panic!(
            "[{}-{}] Invalid tar archive entries",
            krate_name, version.num
        )
    });
    let manifest: Manifest = {
        let path = format!("{}-{}/Cargo.toml", krate_name, version.num);
        let contents = find_file_by_path(&mut entries, Path::new(&path), version, krate_name);
        toml::from_str(&contents).unwrap_or_else(|_| {
            panic!(
                "[{}-{}] Syntax error in manifest file",
                krate_name, version.num
            )
        })
    };

    let rendered = {
        let path = format!(
            "{}-{}/{}",
            krate_name, version.num, manifest.package.readme?
        );
        let contents = find_file_by_path(&mut entries, Path::new(&path), version, krate_name);
        text_to_html(
            &contents,
            manifest
                .package
                .readme_file
                .as_ref()
                .map_or("README.md", |e| &**e),
            manifest.package.repository.as_deref(),
        )
    };
    return Some(rendered);

    #[derive(Deserialize)]
    struct Package {
        readme: Option<String>,
        readme_file: Option<String>,
        repository: Option<String>,
    }

    #[derive(Deserialize)]
    struct Manifest {
        package: Package,
    }
}

/// Search an entry by its path in a Tar archive.
fn find_file_by_path<R: Read>(
    entries: &mut tar::Entries<'_, R>,
    path: &Path,
    version: &Version,
    krate_name: &str,
) -> String {
    let mut file = entries
        .find(|entry| match *entry {
            Err(_) => false,
            Ok(ref file) => {
                let filepath = match file.path() {
                    Ok(p) => p,
                    Err(_) => return false,
                };
                filepath == path
            }
        })
        .unwrap_or_else(|| {
            panic!(
                "[{}-{}] couldn't open file: {}",
                krate_name,
                version.num,
                path.display()
            )
        })
        .unwrap_or_else(|_| {
            panic!(
                "[{}-{}] file is not present: {}",
                krate_name,
                version.num,
                path.display()
            )
        });
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap_or_else(|_| {
        panic!(
            "[{}-{}] Couldn't read file contents",
            krate_name, version.num
        )
    });
    contents
}
<commit_msg>admin/render_readmes.rs to correctly identify the readme_path<commit_after>use crate::{
    config, db,
    models::Version,
    schema::{crates, readme_renderings, versions},
    uploaders::Uploader,
};
use std::{io::Read, path::Path, sync::Arc, thread};

use cargo_registry_markdown::text_to_html;
use chrono::{TimeZone, Utc};
use clap::Clap;
use diesel::{dsl::any, prelude::*};
use flate2::read::GzDecoder;
use reqwest::{blocking::Client, header};
use tar::{self, Archive};

const CACHE_CONTROL_README: &str = "public,max-age=604800";
const USER_AGENT: &str = "crates-admin";

#[derive(Clap, Debug)]
#[clap(
    name = "render-readmes",
    about = "Iterates over every crate versions ever uploaded and (re-)renders their \
        readme using the readme renderer from the cargo_registry crate.",
    after_help = "Warning: this can take a lot of time."
)]
pub struct Opts {
    /// How many versions should be queried and processed at a time.
    #[clap(long, default_value = "25")]
    page_size: usize,

    /// Only rerender readmes that are older than this date.
    #[clap(long)]
    older_than: Option<String>,

    /// Only rerender readmes for the specified crate.
    #[clap(long = "crate")]
    crate_name: Option<String>,
}

pub fn run(opts: Opts) {
    let base_config = Arc::new(config::Base::from_environment());
    let conn = db::connect_now().unwrap();

    let start_time = Utc::now();

    let older_than = if let Some(ref time) = opts.older_than {
        Utc.datetime_from_str(time, "%Y-%m-%d %H:%M:%S")
            .expect("Could not parse --older-than argument as a time")
    } else {
        start_time
    };
    let older_than = older_than.naive_utc();

    println!("Start time:                   {}", start_time);
    println!("Rendering readmes older than: {}", older_than);

    let mut query = versions::table
        .inner_join(crates::table)
        .left_outer_join(readme_renderings::table)
        .filter(
            readme_renderings::rendered_at
                .lt(older_than)
                .or(readme_renderings::version_id.is_null()),
        )
        .select(versions::id)
        .into_boxed();

    if let Some(crate_name) = opts.crate_name {
        println!("Rendering readmes for {}", crate_name);
        query = query.filter(crates::name.eq(crate_name));
    }

    let version_ids: Vec<i32> = query.load(&conn).expect("error loading version ids");

    let total_versions = version_ids.len();
    println!("Rendering {} versions", total_versions);

    let page_size = opts.page_size;

    let total_pages = total_versions / page_size;
    let total_pages = if total_versions % page_size == 0 {
        total_pages
    } else {
        total_pages + 1
    };

    let client = Client::new();

    for (page_num, version_ids_chunk) in version_ids.chunks(page_size).enumerate() {
        println!(
            "= Page {} of {} ==================================",
            page_num + 1,
            total_pages
        );

        let versions: Vec<(Version, String)> = versions::table
            .inner_join(crates::table)
            .filter(versions::id.eq(any(version_ids_chunk)))
            .select((versions::all_columns, crates::name))
            .load(&conn)
            .expect("error loading versions");

        let mut tasks = Vec::with_capacity(page_size as usize);
        for (version, krate_name) in versions {
            Version::record_readme_rendering(version.id, &conn).unwrap_or_else(|_| {
                panic!(
                    "[{}-{}] Couldn't record rendering time",
                    krate_name, version.num
                )
            });
            let client = client.clone();
            let base_config = base_config.clone();
            let handle = thread::spawn(move || {
                println!("[{}-{}] Rendering README...", krate_name, version.num);
                let readme = get_readme(base_config.uploader(), &client, &version, &krate_name);
                if readme.is_none() {
                    return;
                }
                let readme = readme.unwrap();
                let content_length = readme.len() as u64;
                let content = std::io::Cursor::new(readme);
                let readme_path = format!("readmes/{0}/{0}-{1}.html", krate_name, version.num);
                let mut extra_headers = header::HeaderMap::new();
                extra_headers.insert(
                    header::CACHE_CONTROL,
                    header::HeaderValue::from_static(CACHE_CONTROL_README),
                );
                base_config
                    .uploader()
                    .upload(
                        &client,
                        &readme_path,
                        content,
                        content_length,
                        "text/html",
                        extra_headers,
                    )
                    .unwrap_or_else(|_| {
                        panic!(
                            "[{}-{}] Couldn't upload file to S3",
                            krate_name, version.num
                        )
                    });
            });
            tasks.push(handle);
        }
        for handle in tasks {
            if let Err(err) = handle.join() {
                println!("Thread panicked: {:?}", err);
            }
        }
    }
}

/// Renders the readme of an uploaded crate version.
fn get_readme(
    uploader: &Uploader,
    client: &Client,
    version: &Version,
    krate_name: &str,
) -> Option<String> {
    let location = uploader.crate_location(krate_name, &version.num.to_string());

    let location = match uploader {
        Uploader::S3 { .. } => location,
        Uploader::Local => format!("http://localhost:8888/{}", location),
    };

    let mut extra_headers = header::HeaderMap::new();
    extra_headers.insert(
        header::USER_AGENT,
        header::HeaderValue::from_static(USER_AGENT),
    );
    let response = match client.get(&location).headers(extra_headers).send() {
        Ok(r) => r,
        Err(err) => {
            println!(
                "[{}-{}] Unable to fetch crate: {}",
                krate_name, version.num, err
            );
            return None;
        }
    };

    if !response.status().is_success() {
        println!(
            "[{}-{}] Failed to get a 200 response: {}",
            krate_name,
            version.num,
            response.text().unwrap()
        );
        return None;
    }

    let reader = GzDecoder::new(response);
    let mut archive = Archive::new(reader);
    let mut entries = archive.entries().unwrap_or_else(|_| {
        panic!(
            "[{}-{}] Invalid tar archive entries",
            krate_name, version.num
        )
    });
    let manifest: Manifest = {
        let path = format!("{}-{}/Cargo.toml", krate_name, version.num);
        let contents = find_file_by_path(&mut entries, Path::new(&path), version, krate_name);
        toml::from_str(&contents).unwrap_or_else(|_| {
            panic!(
                "[{}-{}] Syntax error in manifest file",
                krate_name, version.num
            )
        })
    };

    let rendered = {
        let readme_path = manifest.package.readme.as_ref()?;
        let path = format!("{}-{}/{}", krate_name, version.num, readme_path);
        let contents = find_file_by_path(&mut entries, Path::new(&path), version, krate_name);
        text_to_html(
            &contents,
            readme_path,
            manifest.package.repository.as_deref(),
        )
    };
    return Some(rendered);

    #[derive(Debug, Deserialize)]
    struct Package {
        readme: Option<String>,
        repository: Option<String>,
    }

    #[derive(Debug, Deserialize)]
    struct Manifest {
        package: Package,
    }
}

/// Search an entry by its path in a Tar archive.
fn find_file_by_path<R: Read>(
    entries: &mut tar::Entries<'_, R>,
    path: &Path,
    version: &Version,
    krate_name: &str,
) -> String {
    let mut file = entries
        .find(|entry| match *entry {
            Err(_) => false,
            Ok(ref file) => {
                let filepath = match file.path() {
                    Ok(p) => p,
                    Err(_) => return false,
                };
                filepath == path
            }
        })
        .unwrap_or_else(|| {
            panic!(
                "[{}-{}] couldn't open file: {}",
                krate_name,
                version.num,
                path.display()
            )
        })
        .unwrap_or_else(|_| {
            panic!(
                "[{}-{}] file is not present: {}",
                krate_name,
                version.num,
                path.display()
            )
        });
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap_or_else(|_| {
        panic!(
            "[{}-{}] Couldn't read file contents",
            krate_name, version.num
        )
    });
    contents
}
<|endoftext|>