<commit_before>extern crate lp_modeler;

use std::process;
use std::collections::HashMap;

use lp_modeler::variables::*;
use lp_modeler::variables::LpExpression::*;
use lp_modeler::operations::LpOperations;
use lp_modeler::problem::{LpObjective, LpProblem, LpFileFormat};
use lp_modeler::solvers::{SolverTrait, CbcSolver};

#[test]
fn test_readme_example_1() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
    problem += 10.0 * a + 20.0 * b;

    problem += (500*a + 1200*b + 1500*c).le(10000);
    problem += (a).le(b);

    let solver = CbcSolver::new();

    match solver.run(&problem) {
        Ok((status, res)) => {
            println!("Status {:?}", status);
            for (name, value) in res.iter() {
                println!("value of {} = {}", name, value);
            }
        },
        Err(msg) => println!("{}", msg),
    }

    let output1 = "\\ One Problem

Maximize
  obj: 10 a + 20 b

Subject To
  c1: 500 a + 1200 b + 1500 c <= 10000
  c2: a - b <= 0

".to_string();
    let output2 = problem.to_lp_file_format();
    let output2 = output2.split("Generals").collect::<Vec<&str>>();
    let output2 = output2[0];
    assert_eq!(output1, output2);
}

#[test]
fn test_readme_example_2() {
    // Problem Data
    let men = vec!["A", "B", "C"];
    let women = vec!["D", "E", "F"];
    let scores: HashMap<(&'static str, &'static str), f32> = [
        (("A", "D"), 50.0),
        (("A", "E"), 75.0),
        (("A", "F"), 75.0),
        (("B", "D"), 60.0),
        (("B", "E"), 95.0),
        (("B", "F"), 80.0),
        (("C", "D"), 60.0),
        (("C", "E"), 70.0),
        (("C", "F"), 80.0),
        ].iter().cloned().collect();

    // Define Problem
    let mut problem = LpProblem::new("Matchmaking", LpObjective::Maximize);

    // Define Variables
    let mut vars = HashMap::new();
    for m in &men{
        for w in &women{
            vars.insert((m, w), LpBinary::new(&format!("{}_{}", m, w)));
        }
    }

    // Define Objective Function
    let mut obj_vec: Vec<LpExpression> = Vec::new();
    for (&(m, w), var) in &vars{
        let obj_coef = scores.get(&(m, w)).unwrap();
        obj_vec.push(*obj_coef * var);
    }
    problem += lp_sum(&obj_vec);

    // Define Constraints
    // Constraint 1: Each man must be assigned to exactly one woman
    for m in &men{
        let mut constr_vec = Vec::new();

        for w in &women{
            constr_vec.push(1.0 * vars.get(&(m, w)).unwrap());
        }

        problem += lp_sum(&constr_vec).equal(1);
    }

    // Constraint 2: Each woman must be assigned to exactly one man
    for w in &women{
        let mut constr_vec = Vec::new();

        for m in &men{
            constr_vec.push(1.0 * vars.get(&(m, w)).unwrap());
        }

        problem += lp_sum(&constr_vec).equal(1);
    }

    // Optionally write to file
    // let result = problem.write_lp("problem.lp");
    // match result{
    //     Ok(_) => println!("Written to file"),
    //     Err(msg) => println!("{}", msg)
    // }

    // Run Solver
    let solver = CbcSolver::new();
    let result = solver.run(&problem);

    // Terminate if error, or assign status & variable values
    assert!(result.is_ok(), result.unwrap_err());
    let (solver_status, var_values) = result.unwrap();

    // Compute final objective function value
    let mut obj_value = 0f32;
    for (&(m, w), var) in &vars{
        let obj_coef = scores.get(&(m, w)).unwrap();
        let var_value = var_values.get(&var.name).unwrap();

        obj_value += obj_coef * var_value;
    }

    // Print output
    println!("Status: {:?}", solver_status);
    println!("Objective Value: {}", obj_value);
    // println!("{:?}", var_values);
    for (var_name, var_value) in &var_values{
        let int_var_value = *var_value as u32;
        if int_var_value == 1{
            println!("{} = {}", var_name, int_var_value);
        }
    }
}<commit_msg>Added further assertions<commit_after>extern crate lp_modeler;

use std::process;
use std::collections::HashMap;

use lp_modeler::variables::*;
use lp_modeler::variables::LpExpression::*;
use lp_modeler::operations::LpOperations;
use lp_modeler::problem::{LpObjective, LpProblem, LpFileFormat};
use lp_modeler::solvers::{SolverTrait, CbcSolver};

#[test]
fn test_readme_example_1() {
    let ref a = LpInteger::new("a");
    let ref b = LpInteger::new("b");
    let ref c = LpInteger::new("c");

    let mut problem = LpProblem::new("One Problem", LpObjective::Maximize);
    problem += 10.0 * a + 20.0 * b;

    problem += (500*a + 1200*b + 1500*c).le(10000);
    problem += (a).le(b);

    let solver = CbcSolver::new();

    match solver.run(&problem) {
        Ok((status, res)) => {
            println!("Status {:?}", status);
            for (name, value) in res.iter() {
                println!("value of {} = {}", name, value);
            }
        },
        Err(msg) => println!("{}", msg),
    }

    let output1 = "\\ One Problem

Maximize
  obj: 10 a + 20 b

Subject To
  c1: 500 a + 1200 b + 1500 c <= 10000
  c2: a - b <= 0

".to_string();
    let output2 = problem.to_lp_file_format();
    let output2 = output2.split("Generals").collect::<Vec<&str>>();
    let output2 = output2[0];
    assert_eq!(output1, output2);
}

#[test]
fn test_readme_example_2() {
    // Problem Data
    let men = vec!["A", "B", "C"];
    let women = vec!["D", "E", "F"];
    let scores: HashMap<(&'static str, &'static str), f32> = [
        (("A", "D"), 50.0),
        (("A", "E"), 75.0),
        (("A", "F"), 75.0),
        (("B", "D"), 60.0),
        (("B", "E"), 95.0),
        (("B", "F"), 80.0),
        (("C", "D"), 60.0),
        (("C", "E"), 70.0),
        (("C", "F"), 80.0),
        ].iter().cloned().collect();

    // Define Problem
    let mut problem = LpProblem::new("Matchmaking", LpObjective::Maximize);

    // Define Variables
    let mut vars = HashMap::new();
    for m in &men{
        for w in &women{
            vars.insert((m, w), LpBinary::new(&format!("{}_{}", m, w)));
        }
    }

    // Define Objective Function
    let mut obj_vec: Vec<LpExpression> = Vec::new();
    for (&(m, w), var) in &vars{
        let obj_coef = scores.get(&(m, w)).unwrap();
        obj_vec.push(*obj_coef * var);
    }
    problem += lp_sum(&obj_vec);

    // Define Constraints
    // Constraint 1: Each man must be assigned to exactly one woman
    for m in &men{
        let mut constr_vec = Vec::new();

        for w in &women{
            constr_vec.push(1.0 * vars.get(&(m, w)).unwrap());
        }

        problem += lp_sum(&constr_vec).equal(1);
    }

    // Constraint 2: Each woman must be assigned to exactly one man
    for w in &women{
        let mut constr_vec = Vec::new();

        for m in &men{
            constr_vec.push(1.0 * vars.get(&(m, w)).unwrap());
        }

        problem += lp_sum(&constr_vec).equal(1);
    }

    // Optionally write to file
    // let result = problem.write_lp("problem.lp");
    // match result{
    //     Ok(_) => println!("Written to file"),
    //     Err(msg) => println!("{}", msg)
    // }

    // Run Solver
    let solver = CbcSolver::new();
    let result = solver.run(&problem);

    // Terminate if error, or assign status & variable values
    assert!(result.is_ok(), result.unwrap_err());
    let (solver_status, var_values) = result.unwrap();

    // Compute final objective function value
    let mut obj_value = 0f32;
    for (&(m, w), var) in &vars{
        let obj_coef = scores.get(&(m, w)).unwrap();
        let var_value = var_values.get(&var.name).unwrap();

        obj_value += obj_coef * var_value;
    }

    // Print output
    println!("Status: {:?}", solver_status);
    println!("Objective Value: {}", obj_value);
    // println!("{:?}", var_values);
    for (var_name, var_value) in &var_values{
        let int_var_value = *var_value as u32;
        if int_var_value == 1{
            println!("{} = {}", var_name, int_var_value);
        }
    }

    assert_eq!(solver_status, lp_modeler::solvers::Status::Optimal);
    assert_eq!(obj_value, 230f32);
    assert_eq!(*var_values.get("A_F").unwrap(), 1f32);
    assert_eq!(*var_values.get("B_E").unwrap(), 1f32);
    assert_eq!(*var_values.get("C_D").unwrap(), 1f32);
}<|endoftext|>


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

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

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 = buf.get(0).unwrap_or(&0) % 2 == 0;

    let ops: Vec<Op> = buf
        .chunks(2)
        .map(|chunk| {
            let mut seed = [0u8; 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, 0, 100, false, use_compression)
    }) {
        Ok(_) => {}
        Err(_e) => panic!("TODO"),
    }
}

impl Arbitrary for Key {
    fn arbitrary<G: Gen>(g: &mut G) -> Key {
        if g.gen::<bool>() {
            let gs = g.size();
            let gamma = Gamma::new(0.3, gs as f64);
            let v = gamma.sample(&mut rand::thread_rng());
            let len = if v > 30000.0 {
                30000
            } else if v < 1. && v > 0.0001 {
                1
            } else {
                v as usize
            };

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

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

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

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

            Key(inner)
        }
    }

    fn shrink(&self) -> Box<Iterator<Item = Key>> {
        // 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)| Key(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, usize),
    Restart,
}

use self::Op::*;

impl Op {
    pub fn is_restart(&self) -> bool {
        if let Restart = self {
            true
        } else {
            false
        }
    }
}

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Op {
        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(0, 40)),
            _ => panic!("impossible choice"),
        }
    }

    fn shrink(&self) -> Box<Iterator<Item = Op>> {
        match *self {
            Set(ref k, v) => Box::new(k.shrink().map(move |sk| Set(sk, v))),
            Merge(ref k, v) => Box::new(k.shrink().map(move |k| 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> {
    let ret = vec![(u >> 8) as u8, u as u8];
    ret
}

// 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>,
    blink_node_exponent: u8,
    snapshot_after: u8,
    flusher: bool,
    use_compression: bool,
) -> bool {
    super::setup_logger();

    use self::*;
    let config = ConfigBuilder::new()
        .async_io(false)
        .temporary(true)
        .use_compression(use_compression)
        .snapshot_after_ops(u64::from(snapshot_after) + 1)
        .flush_every_ms(if flusher { Some(1) } else { None })
        .io_buf_size(10000)
        .blink_node_split_size(1 << std::cmp::min(blink_node_exponent, 20))
        .cache_capacity(40)
        .cache_bits(0)
        .merge_operator(test_merge_operator)
        .idgen_persist_interval(1)
        .build();

    let mut tree = sled::Db::start(config.clone()).unwrap();
    let mut reference: BTreeMap<Key, u16> = BTreeMap::new();

    for op in ops.into_iter() {
        match op {
            Set(k, v) => {
                tree.set(&k.0, vec![0, v]).unwrap();
                reference.insert(k.clone(), u16::from(v));
            }
            Merge(k, v) => {
                tree.merge(&k.0, vec![v]).unwrap();
                let entry = reference.entry(k).or_insert(0u16);
                *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.del(&*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.set(&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) => {
                let mut tree_iter =
                    tree.range(&*k.0..).take(len).map(|res| res.unwrap());
                let ref_iter = reference
                    .iter()
                    .filter(|&(ref rk, _rv)| **rk >= k)
                    .take(len)
                    .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
                    );
                }
            }
            Restart => {
                drop(tree);
                tree = sled::Db::start(config.clone()).unwrap();
            }
        }
    }

    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>Actually check set return values in quickcheck<commit_after>use std::{collections::BTreeMap, fmt, panic};

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

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 = buf.get(0).unwrap_or(&0) % 2 == 0;

    let ops: Vec<Op> = buf
        .chunks(2)
        .map(|chunk| {
            let mut seed = [0u8; 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, 0, 100, false, use_compression)
    }) {
        Ok(_) => {}
        Err(_e) => panic!("TODO"),
    }
}

impl Arbitrary for Key {
    fn arbitrary<G: Gen>(g: &mut G) -> Key {
        if g.gen::<bool>() {
            let gs = g.size();
            let gamma = Gamma::new(0.3, gs as f64);
            let v = gamma.sample(&mut rand::thread_rng());
            let len = if v > 30000.0 {
                30000
            } else if v < 1. && v > 0.0001 {
                1
            } else {
                v as usize
            };

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

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

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

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

            Key(inner)
        }
    }

    fn shrink(&self) -> Box<Iterator<Item = Key>> {
        // 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)| Key(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, usize),
    Restart,
}

use self::Op::*;

impl Op {
    pub fn is_restart(&self) -> bool {
        if let Restart = self {
            true
        } else {
            false
        }
    }
}

impl Arbitrary for Op {
    fn arbitrary<G: Gen>(g: &mut G) -> Op {
        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(0, 40)),
            _ => panic!("impossible choice"),
        }
    }

    fn shrink(&self) -> Box<Iterator<Item = Op>> {
        match *self {
            Set(ref k, v) => Box::new(k.shrink().map(move |sk| Set(sk, v))),
            Merge(ref k, v) => Box::new(k.shrink().map(move |k| 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> {
    let ret = vec![(u >> 8) as u8, u as u8];
    ret
}

// 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>,
    blink_node_exponent: u8,
    snapshot_after: u8,
    flusher: bool,
    use_compression: bool,
) -> bool {
    super::setup_logger();

    use self::*;
    let config = ConfigBuilder::new()
        .async_io(false)
        .temporary(true)
        .use_compression(use_compression)
        .snapshot_after_ops(u64::from(snapshot_after) + 1)
        .flush_every_ms(if flusher { Some(1) } else { None })
        .io_buf_size(10000)
        .blink_node_split_size(1 << std::cmp::min(blink_node_exponent, 20))
        .cache_capacity(40)
        .cache_bits(0)
        .merge_operator(test_merge_operator)
        .idgen_persist_interval(1)
        .build();

    let mut tree = sled::Db::start(config.clone()).unwrap();
    let mut reference: BTreeMap<Key, u16> = BTreeMap::new();

    for op in ops.into_iter() {
        match op {
            Set(k, v) => {
                let old_actual = tree.set(&k.0, vec![0, v]).unwrap();
                let old_reference = reference.insert(k.clone(), u16::from(v));
                assert_eq!(
                    old_actual.map(|v| v[1] as u8),
                    old_reference.map(|v| v as u8)
                );
            }
            Merge(k, v) => {
                tree.merge(&k.0, vec![v]).unwrap();
                let entry = reference.entry(k).or_insert(0u16);
                *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.del(&*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.set(&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) => {
                let mut tree_iter =
                    tree.range(&*k.0..).take(len).map(|res| res.unwrap());
                let ref_iter = reference
                    .iter()
                    .filter(|&(ref rk, _rv)| **rk >= k)
                    .take(len)
                    .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
                    );
                }
            }
            Restart => {
                drop(tree);
                tree = sled::Db::start(config.clone()).unwrap();
            }
        }
    }

    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(&[]);
}
<|endoftext|>


<commit_before>/// Markdown Fenced Code Block Highlighting

#[cfg(feature = "syntax")]
mod syntax;
#[cfg(feature = "syntax")]
pub use syntax::*;

pub use raw::*;
mod raw;
<commit_msg>docs: Add top-level doc<commit_after>//! Markdown Fenced Code Block Highlighting

#[cfg(feature = "syntax")]
mod syntax;
#[cfg(feature = "syntax")]
pub use syntax::*;

pub use raw::*;
mod raw;
<|endoftext|>


<commit_before>use std::fmt::{Debug, Display, Formatter};
use std::fmt;
use std::convert::{From, Into};
use std::str::FromStr;

#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Eq)]
#[derive(Hash)]
/**
 * File ID type
 *
 * Currently only UUID is available. Maybe this will be the only type available at all.
 */
pub enum FileIDType {
    UUID,
}

pub enum FileIDTypeParseError {
    UnknownType
}

impl FromStr for FileIDType {
    type Err = FileIDTypeParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "UUID" => Ok(FileIDType::UUID),
            _ => Err(FileIDTypeParseError::UnknownType)
        }
    }
}

impl Into<String> for FileIDType {

    fn into(self) -> String {
        match self {
            FileIDType::UUID    => String::from("UUID"),
        }
    }
}

impl Display for FileIDType {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileIDType::UUID => try!(write!(fmt, "UUID")),
        }
        Ok(())
    }
}

<commit_msg>Remove unused import<commit_after>use std::fmt::{Display, Formatter};
use std::fmt;
use std::convert::{From, Into};
use std::str::FromStr;

#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Eq)]
#[derive(Hash)]
/**
 * File ID type
 *
 * Currently only UUID is available. Maybe this will be the only type available at all.
 */
pub enum FileIDType {
    UUID,
}

pub enum FileIDTypeParseError {
    UnknownType
}

impl FromStr for FileIDType {
    type Err = FileIDTypeParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "UUID" => Ok(FileIDType::UUID),
            _ => Err(FileIDTypeParseError::UnknownType)
        }
    }
}

impl Into<String> for FileIDType {

    fn into(self) -> String {
        match self {
            FileIDType::UUID    => String::from("UUID"),
        }
    }
}

impl Display for FileIDType {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileIDType::UUID => try!(write!(fmt, "UUID")),
        }
        Ok(())
    }
}

<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::str::{self, FromStr};

// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
    let minor = match rustc_minor_version() {
        Some(minor) => minor,
        None => return,
    };

    let target = env::var("TARGET").unwrap();
    let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";

    // 128-bit integers stabilized in Rust 1.26:
    // https://blog.rust-lang.org/2018/05/10/Rust-1.26.html
    //
    // Disabled on Emscripten targets as Emscripten doesn't
    // currently support integers larger than 64 bits.
    if minor >= 26 && !emscripten {
        println!("cargo:rustc-cfg=integer128");
    }

    // #[must_use] on functions stabilized in Rust 1.27:
    // https://blog.rust-lang.org/2018/06/21/Rust-1.27.html
    if minor >= 27 {
        println!("cargo:rustc-cfg=must_use_return");
    }

    // MaybeUninit<T> stabilized in Rust 1.36:
    // https://blog.rust-lang.org/2019/07/04/Rust-1.36.0.html
    if minor >= 36 {
        println!("cargo:rustc-cfg=maybe_uninit");
    }
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = match env::var_os("RUSTC") {
        Some(rustc) => rustc,
        None => return None,
    };

    let output = match Command::new(rustc).arg("--version").output() {
        Ok(output) => output,
        Err(_) => return None,
    };

    let version = match str::from_utf8(&output.stdout) {
        Ok(version) => version,
        Err(_) => return None,
    };

    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }

    let next = match pieces.next() {
        Some(next) => next,
        None => return None,
    };

    u32::from_str(next).ok()
}
<commit_msg>Use question mark on Option in build script<commit_after>use std::env;
use std::process::Command;
use std::str::{self, FromStr};

// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
    let minor = match rustc_minor_version() {
        Some(minor) => minor,
        None => return,
    };

    let target = env::var("TARGET").unwrap();
    let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten";

    // 128-bit integers stabilized in Rust 1.26:
    // https://blog.rust-lang.org/2018/05/10/Rust-1.26.html
    //
    // Disabled on Emscripten targets as Emscripten doesn't
    // currently support integers larger than 64 bits.
    if minor >= 26 && !emscripten {
        println!("cargo:rustc-cfg=integer128");
    }

    // #[must_use] on functions stabilized in Rust 1.27:
    // https://blog.rust-lang.org/2018/06/21/Rust-1.27.html
    if minor >= 27 {
        println!("cargo:rustc-cfg=must_use_return");
    }

    // MaybeUninit<T> stabilized in Rust 1.36:
    // https://blog.rust-lang.org/2019/07/04/Rust-1.36.0.html
    if minor >= 36 {
        println!("cargo:rustc-cfg=maybe_uninit");
    }
}

fn rustc_minor_version() -> Option<u32> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    let next = pieces.next()?;
    u32::from_str(next).ok()
}
<|endoftext|>


<commit_before>extern crate cheddar;

fn main() {
    cheddar::Cheddar::new().expect("could not read manifest")
        .run_build("target/ctehxk2.h");
}
<commit_msg>fix linting<commit_after>extern crate cheddar;

fn main() {
    cheddar::Cheddar::new()
        .expect("could not read manifest")
        .run_build("target/ctehxk2.h");
}
<|endoftext|>


<commit_before>fn main() {
    use std::process::Command;
    Command::new("cmake").args(&["."]).current_dir("bobyqa-cpp").status().unwrap();
    Command::new("make").current_dir("bobyqa-cpp").status().unwrap();
    println!("cargo:rustc-link-search=native=bobyqa-cpp/lib");
    println!("cargo:rustc-link-lib=static=bobyqa");
}
<commit_msg>Use absolute paths in build script<commit_after>fn main() {
    use std::path::Path;
    use std::process::Command;
    let dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("bobyqa-cpp");
    Command::new("cmake").args(&["."]).current_dir(&dir).status().unwrap();
    Command::new("make").current_dir(&dir).status().unwrap();
    println!("cargo:rustc-link-search=native={}", dir.join("lib").display());
    println!("cargo:rustc-link-lib=static=bobyqa");
}
<|endoftext|>


<commit_before>use std::process::Command;
use std::env;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    println!("cargo:rustc-link-search=native={}", out_dir);
    // Cargo build --release 把build.rs的输出当参数(link搜索路径,-vv可以看到)。
    // Cargo build --release -vv 可以看到println的内容。。
    if cfg!(target_os = "windows") {
        Command::new("windres")
            .arg("config/favicon.rc")
            .arg("-o")
            .arg(&format!("{}/favicon.o", out_dir))
            .status()
            .unwrap();
    }
}
<commit_msg>fix build.rs about point_width on windows.<commit_after>fn main() {
    platform::main();
}

#[cfg(unix)]
mod platform {
    pub fn main() {}
}

#[cfg(windows)]
mod platform {
    use std::process::Command;
    use std::env;

    pub fn main() {
        let out_dir = env::var("OUT_DIR").unwrap();
        println!("cargo:rustc-link-search=native={}", out_dir);
        // Cargo build --release 把build.rs的输出当参数(link搜索路径,-vv可以看到)。
        // Cargo build --release -vv 可以看到println的内容。。
        Command::new("windres")
            .arg("config/favicon.rc")
            .arg("--target")
            .arg(target())
            .arg("-o")
            .arg(&format!("{}/favicon.o", out_dir))
            .status()
            .unwrap();
    }

    // build can't use if cfg!(target-point-width="64"), instead by env::var()
    fn target() -> &'static str {
        if env::var("TARGET").unwrap().contains("x86_64") {
            "pe-x86-64"
        } else {
            "pe-i386"
        }
    }
}<|endoftext|>


<commit_before>extern crate bindgen;

fn sdk_path(target: &str) -> Result<String, std::io::Error> {
    // Use environment variable if set
    println!("cargo:rerun-if-env-changed=COREAUDIO_SDK_PATH");
    if let Ok(path) = std::env::var("COREAUDIO_SDK_PATH") {
        return Ok(path);
    }

    use std::process::Command;

    let sdk = if target.contains("apple-darwin") {
        "macosx"
    } else if target == "x86_64-apple-ios" || target == "i386-apple-ios" {
        "iphonesimulator"
    } else if target == "aarch64-apple-ios"
        || target == "armv7-apple-ios"
        || target == "armv7s-apple-ios"
    {
        "iphoneos"
    } else {
        unreachable!();
    };
    let output = Command::new("xcrun")
        .args(&["--sdk", sdk, "--show-sdk-path"])
        .output()?
        .stdout;
    let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcrun`");
    Ok(prefix_str.trim_end().to_string())
}

fn build(sdk_path: Option<&str>, target: &str) {
    // Generate one large set of bindings for all frameworks.
    //
    // We do this rather than generating a module per framework as some frameworks depend on other
    // frameworks and in turn share types. To ensure all types are compatible across each
    // framework, we feed all headers to bindgen at once.
    //
    // Only link to each framework and include their headers if their features are enabled and they
    // are available on the target os.

    use std::env;
    use std::path::PathBuf;

    let mut headers: Vec<&'static str> = vec![];

    #[cfg(feature = "audio_toolbox")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioToolbox/AudioToolbox.h");
    }

    #[cfg(feature = "audio_unit")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioUnit/AudioUnit.h");
    }

    #[cfg(feature = "core_audio")]
    {
        println!("cargo:rustc-link-lib=framework=CoreAudio");

        if target.contains("apple-ios") {
            headers.push("CoreAudio/CoreAudioTypes.h");
        } else {
            headers.push("CoreAudio/CoreAudio.h");
        }
    }

    #[cfg(feature = "open_al")]
    {
        println!("cargo:rustc-link-lib=framework=OpenAL");
        headers.push("OpenAL/al.h");
        headers.push("OpenAL/alc.h");
    }

    #[cfg(all(feature = "core_midi"))]
    {
        if target.contains("apple-darwin") {
            println!("cargo:rustc-link-lib=framework=CoreMIDI");
            headers.push("CoreMIDI/CoreMIDI.h");
        }
    }

    println!("cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS");
    // Get the cargo out directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found"));

    // Begin building the bindgen params.
    let mut builder = bindgen::Builder::default();

    // See https://github.com/rust-lang/rust-bindgen/issues/1211
    // Technically according to the llvm mailing list, the argument to clang here should be
    // -arch arm64 but it looks cleaner to just change the target.
    let target = if target == "aarch64-apple-ios" {
        "arm64-apple-ios"
    } else if target == "aarch64-apple-darwin" {
        "arm64-apple-darwin"
    } else {
        target
    };
    builder = builder.size_t_is_usize(true);

    builder = builder.clang_args(&[&format!("--target={}", target)]);

    if let Some(sdk_path) = sdk_path {
        builder = builder.clang_args(&["-isysroot", sdk_path]);
    }
    if target.contains("apple-ios") {
        // time.h as has a variable called timezone that conflicts with some of the objective-c
        // calls from NSCalendar.h in the Foundation framework. This removes that one variable.
        builder = builder.blacklist_item("timezone");
        builder = builder.blacklist_item("objc_object");
    }

    let meta_header: Vec<_> = headers
        .iter()
        .map(|h| format!("#include <{}>\n", h))
        .collect();

    builder = builder.header_contents("coreaudio.h", &meta_header.concat());

    // Generate the bindings.
    builder = builder.trust_clang_mangling(false).derive_default(true);

    let bindings = builder.generate().expect("unable to generate bindings");

    // Write them to the crate root.
    bindings
        .write_to_file(out_dir.join("coreaudio.rs"))
        .expect("could not write bindings");
}

fn main() {
    let target = std::env::var("TARGET").unwrap();
    if !(target.contains("apple-darwin") || target.contains("apple-ios")) {
        panic!("coreaudio-sys requires macos or ios target");
    }

    let directory = sdk_path(&target).ok();
    build(directory.as_ref().map(String::as_ref), &target);
}
<commit_msg>Add support for aarch64-apple-ios-sim<commit_after>extern crate bindgen;

fn sdk_path(target: &str) -> Result<String, std::io::Error> {
    // Use environment variable if set
    println!("cargo:rerun-if-env-changed=COREAUDIO_SDK_PATH");
    if let Ok(path) = std::env::var("COREAUDIO_SDK_PATH") {
        return Ok(path);
    }

    use std::process::Command;

    let sdk = if target.contains("apple-darwin") {
        "macosx"
    } else if target == "x86_64-apple-ios"
        || target == "i386-apple-ios"
        || target == "aarch64-apple-ios-sim"
    {
        "iphonesimulator"
    } else if target == "aarch64-apple-ios"
        || target == "armv7-apple-ios"
        || target == "armv7s-apple-ios"
    {
        "iphoneos"
    } else {
        unreachable!();
    };
    let output = Command::new("xcrun")
        .args(&["--sdk", sdk, "--show-sdk-path"])
        .output()?
        .stdout;
    let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcrun`");
    Ok(prefix_str.trim_end().to_string())
}

fn build(sdk_path: Option<&str>, target: &str) {
    // Generate one large set of bindings for all frameworks.
    //
    // We do this rather than generating a module per framework as some frameworks depend on other
    // frameworks and in turn share types. To ensure all types are compatible across each
    // framework, we feed all headers to bindgen at once.
    //
    // Only link to each framework and include their headers if their features are enabled and they
    // are available on the target os.

    use std::env;
    use std::path::PathBuf;

    let mut headers: Vec<&'static str> = vec![];

    #[cfg(feature = "audio_toolbox")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioToolbox/AudioToolbox.h");
    }

    #[cfg(feature = "audio_unit")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioUnit/AudioUnit.h");
    }

    #[cfg(feature = "core_audio")]
    {
        println!("cargo:rustc-link-lib=framework=CoreAudio");

        if target.contains("apple-ios") {
            headers.push("CoreAudio/CoreAudioTypes.h");
        } else {
            headers.push("CoreAudio/CoreAudio.h");
        }
    }

    #[cfg(feature = "open_al")]
    {
        println!("cargo:rustc-link-lib=framework=OpenAL");
        headers.push("OpenAL/al.h");
        headers.push("OpenAL/alc.h");
    }

    #[cfg(all(feature = "core_midi"))]
    {
        if target.contains("apple-darwin") {
            println!("cargo:rustc-link-lib=framework=CoreMIDI");
            headers.push("CoreMIDI/CoreMIDI.h");
        }
    }

    println!("cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS");
    // Get the cargo out directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found"));

    // Begin building the bindgen params.
    let mut builder = bindgen::Builder::default();

    // See https://github.com/rust-lang/rust-bindgen/issues/1211
    // Technically according to the llvm mailing list, the argument to clang here should be
    // -arch arm64 but it looks cleaner to just change the target.
    let target = if target == "aarch64-apple-ios" {
        "arm64-apple-ios"
    } else if target == "aarch64-apple-darwin" {
        "arm64-apple-darwin"
    } else {
        target
    };
    builder = builder.size_t_is_usize(true);

    builder = builder.clang_args(&[&format!("--target={}", target)]);

    if let Some(sdk_path) = sdk_path {
        builder = builder.clang_args(&["-isysroot", sdk_path]);
    }
    if target.contains("apple-ios") {
        // time.h as has a variable called timezone that conflicts with some of the objective-c
        // calls from NSCalendar.h in the Foundation framework. This removes that one variable.
        builder = builder.blacklist_item("timezone");
        builder = builder.blacklist_item("objc_object");
    }

    let meta_header: Vec<_> = headers
        .iter()
        .map(|h| format!("#include <{}>\n", h))
        .collect();

    builder = builder.header_contents("coreaudio.h", &meta_header.concat());

    // Generate the bindings.
    builder = builder.trust_clang_mangling(false).derive_default(true);

    let bindings = builder.generate().expect("unable to generate bindings");

    // Write them to the crate root.
    bindings
        .write_to_file(out_dir.join("coreaudio.rs"))
        .expect("could not write bindings");
}

fn main() {
    let target = std::env::var("TARGET").unwrap();
    if !(target.contains("apple-darwin") || target.contains("apple-ios")) {
        panic!("coreaudio-sys requires macos or ios target");
    }

    let directory = sdk_path(&target).ok();
    build(directory.as_ref().map(String::as_ref), &target);
}
<|endoftext|>


<commit_before>pub mod actions;
pub mod boot_source;
pub mod drive;
pub mod logger;
pub mod machine_configuration;
pub mod net;

use serde_json::Value;
use std::result;

use hyper;
use hyper::{Method, StatusCode};

use http_service::{empty_response, json_fault_message, json_response};
use vmm::{ErrorKind, OutcomeReceiver, VmmAction, VmmActionError, VmmData};

pub enum ParsedRequest {
    GetInstanceInfo,
    GetMMDS,
    PatchMMDS(Value),
    PutMMDS(Value),
    Sync(VmmAction, OutcomeReceiver),
}

pub trait IntoParsedRequest {
    fn into_parsed_request(
        self,
        resource_id: Option<String>,
        method: Method,
    ) -> result::Result<ParsedRequest, String>;
}

// Sync requests have outcomes which implement this trait. The idea is for each outcome to be a
// struct which is cheaply and quickly instantiated by the VMM thread, then passed back the the API
// thread, and then unpacked into a http response using the implementation of
// the generate_response() method.
pub trait GenerateHyperResponse {
    fn generate_response(&self) -> hyper::Response;
}

impl GenerateHyperResponse for result::Result<VmmData, VmmActionError> {
    fn generate_response(&self) -> hyper::Response {
        match *self {
            Ok(ref data) => data.generate_response(),
            Err(ref error) => error.generate_response(),
        }
    }
}

impl GenerateHyperResponse for VmmData {
    fn generate_response(&self) -> hyper::Response {
        match *self {
            VmmData::MachineConfiguration(ref machine_config) => machine_config.generate_response(),
            VmmData::Empty => empty_response(StatusCode::NoContent),
        }
    }
}

impl GenerateHyperResponse for VmmActionError {
    fn generate_response(&self) -> hyper::Response {
        use self::ErrorKind::*;

        let status_code = match self.get_kind() {
            User => StatusCode::BadRequest,
            Internal => StatusCode::InternalServerError,
        };

        json_response(status_code, json_fault_message(self.to_string()))
    }
}

impl GenerateHyperResponse for () {
    fn generate_response(&self) -> hyper::Response {
        empty_response(StatusCode::NoContent)
    }
}

#[cfg(test)]
impl PartialEq for ParsedRequest {
    fn eq(&self, other: &ParsedRequest) -> bool {
        match (self, other) {
            (
                &ParsedRequest::Sync(ref sync_req, _),
                &ParsedRequest::Sync(ref other_sync_req, _),
            ) => sync_req == other_sync_req,
            (&ParsedRequest::GetInstanceInfo, &ParsedRequest::GetInstanceInfo) => true,
            (&ParsedRequest::GetMMDS, &ParsedRequest::GetMMDS) => true,
            (&ParsedRequest::PutMMDS(ref val), &ParsedRequest::PutMMDS(ref other_val)) => {
                val == other_val
            }
            (&ParsedRequest::PatchMMDS(ref val), &ParsedRequest::PatchMMDS(ref other_val)) => {
                val == other_val
            }
            _ => false,
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate devices;
    extern crate kernel;
    extern crate memory_model;
    extern crate net_util;
    extern crate x86_64;

    use self::devices::virtio::net::Error as VirtioNetError;
    use self::memory_model::GuestMemoryError;
    use self::net_util::TapError;
    use super::*;

    use data_model::vm::{DriveError, VmConfig, VmConfigError};
    use sys_util;
    use vmm::vmm_config::boot_source::BootSourceConfigError;
    use vmm::vmm_config::instance_info::StartMicrovmError;
    use vmm::vmm_config::logger::LoggerConfigError;
    use vmm::vmm_config::net::NetworkInterfaceError;

    use futures::{Future, Stream};
    use hyper::{Body, Response};
    use serde_json;
    use std;

    fn get_body(
        response: Response<Body>,
    ) -> std::result::Result<serde_json::Value, serde_json::Error> {
        let body = response
            .body()
            .map_err(|_| ())
            .fold(vec![], |mut acc, chunk| {
                acc.extend_from_slice(&chunk);
                Ok(acc)
            }).and_then(|v| String::from_utf8(v).map_err(|_| ()));
        serde_json::from_str::<Value>(body.wait().unwrap().as_ref())
    }

    fn check_error_response(error: VmmActionError, status_code: StatusCode) {
        let hyper_resp = Err(error).generate_response();
        assert_eq!(hyper_resp.status(), status_code);
        assert!(get_body(hyper_resp).is_ok());
    }

    #[test]
    fn test_generate_response() {
        // Test OK Empty response from VMM.
        let vmm_resp = Ok(VmmData::Empty);
        let hyper_resp = vmm_resp.generate_response();
        assert_eq!(hyper_resp.status(), StatusCode::NoContent);
        // assert that the body is empty. When the JSON is empty, serde returns and EOF error.
        let body_err = get_body(hyper_resp).unwrap_err();
        assert_eq!(
            body_err.to_string(),
            "EOF while parsing a value at line 1 column 0"
        );

        // Test OK response from VMM that contains the Machine Configuration.
        let vmm_resp = Ok(VmmData::MachineConfiguration(VmConfig::default()));
        let hyper_resp = vmm_resp.generate_response();
        assert_eq!(hyper_resp.status(), StatusCode::Ok);
        let vm_config_json = r#"{
            "vcpu_count": 1,
            "mem_size_mib": 128,
            "ht_enabled": false,
            "cpu_template": "Uninitialized"
        }"#;
        let vm_config_json: serde_json::Value = serde_json::from_str(vm_config_json).unwrap();
        assert_eq!(get_body(hyper_resp).unwrap(), vm_config_json);

        // Tests Error Cases
        // Tests for BootSource Errors.
        let vmm_resp =
            VmmActionError::BootSource(ErrorKind::User, BootSourceConfigError::InvalidKernelPath);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp = VmmActionError::BootSource(
            ErrorKind::User,
            BootSourceConfigError::InvalidKernelCommandLine,
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp = VmmActionError::BootSource(
            ErrorKind::User,
            BootSourceConfigError::UpdateNotAllowedPostBoot,
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);

        // Tests for DriveConfig Errors.
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::CannotOpenBlockDevice);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::InvalidBlockDeviceID);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::InvalidBlockDevicePath);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::BlockDevicePathAlreadyExists);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::OperationNotAllowedPreBoot);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::RootBlockDeviceAlreadyAdded);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::UpdateNotAllowedPostBoot);
        check_error_response(vmm_resp, StatusCode::BadRequest);

        // Tests for Logger Errors.
        let vmm_resp = VmmActionError::Logger(
            ErrorKind::User,
            LoggerConfigError::InitializationFailure(
                "Could not open logging fifo: dummy".to_string(),
            ),
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);

        // Tests for MachineConfig Errors.
        let vmm_resp =
            VmmActionError::MachineConfig(ErrorKind::User, VmConfigError::InvalidVcpuCount);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::MachineConfig(ErrorKind::User, VmConfigError::InvalidMemorySize);
        check_error_response(vmm_resp, StatusCode::BadRequest);

        // Tests for NetworkConfig Errors.
        let vmm_resp = VmmActionError::NetworkConfig(
            ErrorKind::User,
            NetworkInterfaceError::OpenTap(TapError::OpenTun(std::io::Error::from_raw_os_error(
                22,
            ))),
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp = VmmActionError::NetworkConfig(
            ErrorKind::User,
            NetworkInterfaceError::GuestMacAddressInUse(String::from("12:34:56:78:9a:bc")),
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp = VmmActionError::NetworkConfig(
            ErrorKind::User,
            NetworkInterfaceError::UpdateNotAllowedPostBoot,
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);

        // Tests for MicrovmStart Errors.
        // RegisterBlockDevice, RegisterNetDevice, and LegacyIOBus cannot be tested because the
        // device manager is a private module in the vmm crate.
        // ConfigureVm, Vcpu, VcpuConfigure, and VmConfigure cannot be tested because vstate is a
        // private module in the vmm crate.
        let vmm_resp =
            VmmActionError::StartMicrovm(ErrorKind::User, StartMicrovmError::MicroVMAlreadyRunning);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::StartMicrovm(ErrorKind::User, StartMicrovmError::MissingKernelConfig);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::GuestMemory(GuestMemoryError::MemoryNotInitialized),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::KernelCmdline(String::from("dummy error.")),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::CreateBlockDevice(sys_util::Error::new(22)),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::User,
            StartMicrovmError::OpenBlockDevice(std::io::Error::from_raw_os_error(22)),
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::CreateRateLimiter(std::io::Error::from_raw_os_error(22)),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::NetDeviceNotConfigured,
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::CreateNetDevice(VirtioNetError::TapOpen(TapError::OpenTun(
                std::io::Error::from_raw_os_error(22),
            ))),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::DeviceVmRequest(sys_util::Error::new(22)),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::ConfigureSystem(x86_64::Error::E820Configuration),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::User,
            StartMicrovmError::Loader(kernel::loader::Error::BigEndianElfOnLittle),
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::StartMicrovm(ErrorKind::Internal, StartMicrovmError::EventFd);
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp =
            VmmActionError::StartMicrovm(ErrorKind::Internal, StartMicrovmError::RegisterEvent);
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::VcpuSpawn(std::io::Error::from_raw_os_error(11)),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
    }
}
<commit_msg>api_server: removed unused generate reponse<commit_after>pub mod actions;
pub mod boot_source;
pub mod drive;
pub mod logger;
pub mod machine_configuration;
pub mod net;

use serde_json::Value;
use std::result;

use hyper;
use hyper::{Method, StatusCode};

use http_service::{empty_response, json_fault_message, json_response};
use vmm::{ErrorKind, OutcomeReceiver, VmmAction, VmmActionError, VmmData};

pub enum ParsedRequest {
    GetInstanceInfo,
    GetMMDS,
    PatchMMDS(Value),
    PutMMDS(Value),
    Sync(VmmAction, OutcomeReceiver),
}

pub trait IntoParsedRequest {
    fn into_parsed_request(
        self,
        resource_id: Option<String>,
        method: Method,
    ) -> result::Result<ParsedRequest, String>;
}

// Sync requests have outcomes which implement this trait. The idea is for each outcome to be a
// struct which is cheaply and quickly instantiated by the VMM thread, then passed back the the API
// thread, and then unpacked into a http response using the implementation of
// the generate_response() method.
pub trait GenerateHyperResponse {
    fn generate_response(&self) -> hyper::Response;
}

impl GenerateHyperResponse for result::Result<VmmData, VmmActionError> {
    fn generate_response(&self) -> hyper::Response {
        match *self {
            Ok(ref data) => data.generate_response(),
            Err(ref error) => error.generate_response(),
        }
    }
}

impl GenerateHyperResponse for VmmData {
    fn generate_response(&self) -> hyper::Response {
        match *self {
            VmmData::MachineConfiguration(ref machine_config) => machine_config.generate_response(),
            VmmData::Empty => empty_response(StatusCode::NoContent),
        }
    }
}

impl GenerateHyperResponse for VmmActionError {
    fn generate_response(&self) -> hyper::Response {
        use self::ErrorKind::*;

        let status_code = match self.get_kind() {
            User => StatusCode::BadRequest,
            Internal => StatusCode::InternalServerError,
        };

        json_response(status_code, json_fault_message(self.to_string()))
    }
}

#[cfg(test)]
impl PartialEq for ParsedRequest {
    fn eq(&self, other: &ParsedRequest) -> bool {
        match (self, other) {
            (
                &ParsedRequest::Sync(ref sync_req, _),
                &ParsedRequest::Sync(ref other_sync_req, _),
            ) => sync_req == other_sync_req,
            (&ParsedRequest::GetInstanceInfo, &ParsedRequest::GetInstanceInfo) => true,
            (&ParsedRequest::GetMMDS, &ParsedRequest::GetMMDS) => true,
            (&ParsedRequest::PutMMDS(ref val), &ParsedRequest::PutMMDS(ref other_val)) => {
                val == other_val
            }
            (&ParsedRequest::PatchMMDS(ref val), &ParsedRequest::PatchMMDS(ref other_val)) => {
                val == other_val
            }
            _ => false,
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate devices;
    extern crate kernel;
    extern crate memory_model;
    extern crate net_util;
    extern crate x86_64;

    use self::devices::virtio::net::Error as VirtioNetError;
    use self::memory_model::GuestMemoryError;
    use self::net_util::TapError;
    use super::*;

    use data_model::vm::{DriveError, VmConfig, VmConfigError};
    use sys_util;
    use vmm::vmm_config::boot_source::BootSourceConfigError;
    use vmm::vmm_config::instance_info::StartMicrovmError;
    use vmm::vmm_config::logger::LoggerConfigError;
    use vmm::vmm_config::net::NetworkInterfaceError;

    use futures::{Future, Stream};
    use hyper::{Body, Response};
    use serde_json;
    use std;

    fn get_body(
        response: Response<Body>,
    ) -> std::result::Result<serde_json::Value, serde_json::Error> {
        let body = response
            .body()
            .map_err(|_| ())
            .fold(vec![], |mut acc, chunk| {
                acc.extend_from_slice(&chunk);
                Ok(acc)
            }).and_then(|v| String::from_utf8(v).map_err(|_| ()));
        serde_json::from_str::<Value>(body.wait().unwrap().as_ref())
    }

    fn check_error_response(error: VmmActionError, status_code: StatusCode) {
        let hyper_resp = Err(error).generate_response();
        assert_eq!(hyper_resp.status(), status_code);
        assert!(get_body(hyper_resp).is_ok());
    }

    #[test]
    fn test_generate_response() {
        // Test OK Empty response from VMM.
        let vmm_resp = Ok(VmmData::Empty);
        let hyper_resp = vmm_resp.generate_response();
        assert_eq!(hyper_resp.status(), StatusCode::NoContent);
        // assert that the body is empty. When the JSON is empty, serde returns and EOF error.
        let body_err = get_body(hyper_resp).unwrap_err();
        assert_eq!(
            body_err.to_string(),
            "EOF while parsing a value at line 1 column 0"
        );

        // Test OK response from VMM that contains the Machine Configuration.
        let vmm_resp = Ok(VmmData::MachineConfiguration(VmConfig::default()));
        let hyper_resp = vmm_resp.generate_response();
        assert_eq!(hyper_resp.status(), StatusCode::Ok);
        let vm_config_json = r#"{
            "vcpu_count": 1,
            "mem_size_mib": 128,
            "ht_enabled": false,
            "cpu_template": "Uninitialized"
        }"#;
        let vm_config_json: serde_json::Value = serde_json::from_str(vm_config_json).unwrap();
        assert_eq!(get_body(hyper_resp).unwrap(), vm_config_json);

        // Tests Error Cases
        // Tests for BootSource Errors.
        let vmm_resp =
            VmmActionError::BootSource(ErrorKind::User, BootSourceConfigError::InvalidKernelPath);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp = VmmActionError::BootSource(
            ErrorKind::User,
            BootSourceConfigError::InvalidKernelCommandLine,
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp = VmmActionError::BootSource(
            ErrorKind::User,
            BootSourceConfigError::UpdateNotAllowedPostBoot,
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);

        // Tests for DriveConfig Errors.
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::CannotOpenBlockDevice);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::InvalidBlockDeviceID);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::InvalidBlockDevicePath);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::BlockDevicePathAlreadyExists);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::OperationNotAllowedPreBoot);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::RootBlockDeviceAlreadyAdded);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::DriveConfig(ErrorKind::User, DriveError::UpdateNotAllowedPostBoot);
        check_error_response(vmm_resp, StatusCode::BadRequest);

        // Tests for Logger Errors.
        let vmm_resp = VmmActionError::Logger(
            ErrorKind::User,
            LoggerConfigError::InitializationFailure(
                "Could not open logging fifo: dummy".to_string(),
            ),
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);

        // Tests for MachineConfig Errors.
        let vmm_resp =
            VmmActionError::MachineConfig(ErrorKind::User, VmConfigError::InvalidVcpuCount);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::MachineConfig(ErrorKind::User, VmConfigError::InvalidMemorySize);
        check_error_response(vmm_resp, StatusCode::BadRequest);

        // Tests for NetworkConfig Errors.
        let vmm_resp = VmmActionError::NetworkConfig(
            ErrorKind::User,
            NetworkInterfaceError::OpenTap(TapError::OpenTun(std::io::Error::from_raw_os_error(
                22,
            ))),
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp = VmmActionError::NetworkConfig(
            ErrorKind::User,
            NetworkInterfaceError::GuestMacAddressInUse(String::from("12:34:56:78:9a:bc")),
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp = VmmActionError::NetworkConfig(
            ErrorKind::User,
            NetworkInterfaceError::UpdateNotAllowedPostBoot,
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);

        // Tests for MicrovmStart Errors.
        // RegisterBlockDevice, RegisterNetDevice, and LegacyIOBus cannot be tested because the
        // device manager is a private module in the vmm crate.
        // ConfigureVm, Vcpu, VcpuConfigure, and VmConfigure cannot be tested because vstate is a
        // private module in the vmm crate.
        let vmm_resp =
            VmmActionError::StartMicrovm(ErrorKind::User, StartMicrovmError::MicroVMAlreadyRunning);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::StartMicrovm(ErrorKind::User, StartMicrovmError::MissingKernelConfig);
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::GuestMemory(GuestMemoryError::MemoryNotInitialized),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::KernelCmdline(String::from("dummy error.")),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::CreateBlockDevice(sys_util::Error::new(22)),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::User,
            StartMicrovmError::OpenBlockDevice(std::io::Error::from_raw_os_error(22)),
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::CreateRateLimiter(std::io::Error::from_raw_os_error(22)),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::NetDeviceNotConfigured,
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::CreateNetDevice(VirtioNetError::TapOpen(TapError::OpenTun(
                std::io::Error::from_raw_os_error(22),
            ))),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::DeviceVmRequest(sys_util::Error::new(22)),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::ConfigureSystem(x86_64::Error::E820Configuration),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::User,
            StartMicrovmError::Loader(kernel::loader::Error::BigEndianElfOnLittle),
        );
        check_error_response(vmm_resp, StatusCode::BadRequest);
        let vmm_resp =
            VmmActionError::StartMicrovm(ErrorKind::Internal, StartMicrovmError::EventFd);
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp =
            VmmActionError::StartMicrovm(ErrorKind::Internal, StartMicrovmError::RegisterEvent);
        check_error_response(vmm_resp, StatusCode::InternalServerError);
        let vmm_resp = VmmActionError::StartMicrovm(
            ErrorKind::Internal,
            StartMicrovmError::VcpuSpawn(std::io::Error::from_raw_os_error(11)),
        );
        check_error_response(vmm_resp, StatusCode::InternalServerError);
    }
}
<|endoftext|>


<commit_before>/// Render some nice human-readable asciidoc files
use crate::collect_docs::{Example, Field, Struct, Type, TypeName};
use std::io::{Result, Write};

pub trait ToAdoc {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()>;
}

impl ToAdoc for Struct {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        writeln!(w, "// Do not edit this file directly!")?;
        writeln!(
            w,
            "// It was generated using derive-collect-docs and will be updated automatically."
        )?;
        writeln!(w)?;
        writeln!(w, "= {}", self.name)?;
        writeln!(w)?;
        writeln!(w, "{}", self.docs)?;
        writeln!(w)?;
        for example in &self.examples {
            example.write_adoc(w)?;
            writeln!(w)?;
        }
        writeln!(w, ".Fields")?;
        writeln!(w)?;

        for field in &self.fields {
            field.write_adoc(w)?;
        }

        Ok(())
    }
}

impl ToAdoc for Field {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        write!(w, "* `{}`", self.name)?;
        if self.required {
            writeln!(w, " _(required)_")?;
        } else {
            writeln!(w, " _(optional)_")?;
        }
        writeln!(w, "+")?;
        write!(w, "Type: `")?;
        self.r#type.write_adoc(w)?;
        writeln!(w, "`")?;

        let docs = self.docs.replace("\n\n", "\n+\n");
        if !docs.is_empty() {
            writeln!(w, "+")?;
            write!(w, "{}", docs)?;
        }
        if !self.examples.is_empty() {
            writeln!(w, "+")?;
        }
        for example in &self.examples {
            example.write_adoc(w)?;
        }
        if !self.examples.is_empty() {
            writeln!(w)?;
        }

        Ok(())
    }
}

impl ToAdoc for Example {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        writeln!(w, ".Example")?;
        writeln!(w, "[source,{}]", self.lang)?;
        writeln!(w, "----")?;
        writeln!(w, "{}", self.content)?;
        writeln!(w, "----")?;
        Ok(())
    }
}

impl ToAdoc for Type {
    fn write_adoc(&self, mut w: &mut dyn Write) -> Result<()> {
        match self {
            Type::Flat(name) => name.write_adoc(w),
            Type::Nested {
                container_name,
                nested,
            } => {
                container_name.write_adoc(&mut w)?;
                write!(w, "<")?;
                let mut first = true;
                for t in nested {
                    if first {
                        first = false;
                    } else {
                        write!(w, ", ")?;
                    }
                    {
                        t.write_adoc(w)?;
                    }
                }
                write!(w, ">")?;
                Ok(())
            }
        }
    }
}

impl ToAdoc for TypeName {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        match self {
            TypeName::Primitive(name) => {
                let name = match name.as_str() {
                    "BTreeMap" => "Map",
                    "HashMap" => "Map",
                    n => n,
                };
                write!(w, "{}", name)
            }
            TypeName::Link(name) => write!(w, "<<{}>>", name),
        }
    }
}
<commit_msg>Collect docs: Don't render headline for empty section<commit_after>/// Render some nice human-readable asciidoc files
use crate::collect_docs::{Example, Field, Struct, Type, TypeName};
use std::io::{Result, Write};

pub trait ToAdoc {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()>;
}

impl ToAdoc for Struct {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        writeln!(w, "// Do not edit this file directly!")?;
        writeln!(
            w,
            "// It was generated using derive-collect-docs and will be updated automatically."
        )?;
        writeln!(w)?;
        writeln!(w, "= {}", self.name)?;
        writeln!(w)?;
        writeln!(w, "{}", self.docs)?;
        writeln!(w)?;
        for example in &self.examples {
            example.write_adoc(w)?;
            writeln!(w)?;
        }

        if !self.fields.is_empty() {
            writeln!(w, ".Fields")?;
        }
        for field in &self.fields {
            field.write_adoc(w)?;
        }
        writeln!(w)?;

        Ok(())
    }
}

impl ToAdoc for Field {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        write!(w, "* `{}`", self.name)?;
        if self.required {
            writeln!(w, " _(required)_")?;
        } else {
            writeln!(w, " _(optional)_")?;
        }
        writeln!(w, "+")?;
        write!(w, "Type: `")?;
        self.r#type.write_adoc(w)?;
        writeln!(w, "`")?;

        let docs = self.docs.replace("\n\n", "\n+\n");
        if !docs.is_empty() {
            writeln!(w, "+")?;
            write!(w, "{}", docs)?;
        }
        if !self.examples.is_empty() {
            writeln!(w, "+")?;
        }
        for example in &self.examples {
            example.write_adoc(w)?;
        }
        if !self.examples.is_empty() {
            writeln!(w)?;
        }

        Ok(())
    }
}

impl ToAdoc for Example {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        writeln!(w, ".Example")?;
        writeln!(w, "[source,{}]", self.lang)?;
        writeln!(w, "----")?;
        writeln!(w, "{}", self.content)?;
        writeln!(w, "----")?;
        Ok(())
    }
}

impl ToAdoc for Type {
    fn write_adoc(&self, mut w: &mut dyn Write) -> Result<()> {
        match self {
            Type::Flat(name) => name.write_adoc(w),
            Type::Nested {
                container_name,
                nested,
            } => {
                container_name.write_adoc(&mut w)?;
                write!(w, "<")?;
                let mut first = true;
                for t in nested {
                    if first {
                        first = false;
                    } else {
                        write!(w, ", ")?;
                    }
                    {
                        t.write_adoc(w)?;
                    }
                }
                write!(w, ">")?;
                Ok(())
            }
        }
    }
}

impl ToAdoc for TypeName {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        match self {
            TypeName::Primitive(name) => {
                let name = match name.as_str() {
                    "BTreeMap" => "Map",
                    "HashMap" => "Map",
                    n => n,
                };
                write!(w, "{}", name)
            }
            TypeName::Link(name) => write!(w, "<<{}>>", name),
        }
    }
}
<|endoftext|>