<commit_before>
#[derive(Show,PartialEq)]
struct Node<T> {
    payload: T,
    next: Option<Box<Node<T>>>,
    previous: Option<Box<Node<T>>>,
}

impl<T> Node<T> {
    pub fn new(payload: T) -> Node<T> {
        Node::<T> {
            payload: payload,
            next: None,
            previous: None,
        }
    }

    pub fn payload(&self) -> Option<&T> {
        Some(&self.payload)
    }
}

struct LinkedList<T> {
    root: Option<Node<T>>,
}

impl<T> LinkedList<T> {
    pub fn new() -> LinkedList<T> {
        LinkedList::<T> {
            root: None,
        }
    }

    fn add(node: Node<T>) {

        let last_node = &node;

        //loop {
        //    if last_node.payload == None {
        //        last_node = node;
        //        break;
        //    }
        //}
    }
}

#[test]
fn test_node_new() {
    let expected = Node {
        payload: "test",
        next: None,
        previous: None,
    };

    let node: Node<&str> = Node::new("test");

    assert_eq!(expected.payload,  node.payload);
    assert_eq!(expected.next,     node.next);
    assert_eq!(expected.previous, node.previous);
}

#[test]
fn test_node_payload() {
    let node: Node<&str> = Node::new("test");
    assert_eq!(&"test", node.payload().unwrap());
}
<commit_msg>Renamed `previous` field in Node to `prev`<commit_after>
#[derive(Show,PartialEq)]
struct Node<T> {
    payload: T,
    next: Option<Box<Node<T>>>,
    prev: Option<Box<Node<T>>>,
}

impl<T> Node<T> {
    pub fn new(payload: T) -> Node<T> {
        Node::<T> {
            payload: payload,
            next: None,
            prev: None,
        }
    }

    pub fn payload(&self) -> Option<&T> {
        Some(&self.payload)
    }
}

struct LinkedList<T> {
    root: Option<Node<T>>,
}

impl<T> LinkedList<T> {
    pub fn new() -> LinkedList<T> {
        LinkedList::<T> {
            root: None,
        }
    }

    fn add(node: Node<T>) {

        let last_node = &node;

        //loop {
        //    if last_node.payload == None {
        //        last_node = node;
        //        break;
        //    }
        //}
    }
}

#[test]
fn test_node_new() {
    let expected = Node {
        payload: "test",
        next: None,
        prev: None,
    };

    let node: Node<&str> = Node::new("test");

    assert_eq!(expected.payload,  node.payload);
    assert_eq!(expected.next,     node.next);
    assert_eq!(expected.prev,     node.prev);
}

#[test]
fn test_node_payload() {
    let node: Node<&str> = Node::new("test");
    assert_eq!(&"test", node.payload().unwrap());
}
<|endoftext|>


<commit_before>use pyo3;
use pyo3::types::{PyBytes};
use pyo3::prelude::*;

use lancelot::workspace;
use lancelot::arch::{RVA};

#[pymodule]
fn pylancelot(_py: Python, m: &PyModule) -> PyResult<()> {
    #[pyfn(m, "from_bytes")]
    /// from_bytes(filename, buf, /)
    /// --
    ///
    /// Create a workspace from the given bytes.
    ///
    /// Args:
    ///   filename (str): the source filename
    ///   buf (bytes): the bytes containing a PE, shellcode, etc.
    ///
    /// Raises:
    ///   ValueError: if failed to create the workspace. TODO: more specific.
    ///
    fn from_bytes(_py: Python, filename: String, buf: &PyBytes) -> PyResult<PyWorkspace> {
        let ws = match workspace::Workspace::from_bytes(&filename, buf.as_bytes()).load() {
            Err(_) => return Err(pyo3::exceptions::ValueError::py_err("failed to create workspace")),
            Ok(ws) => ws,
        };
        Ok(PyWorkspace{ws})
    }

    #[pyclass]
    pub struct PyWorkspace {
        ws: workspace::Workspace
    }

    #[pyclass]
    pub struct PySection {
        #[pyo3(get)]
        pub addr: i64,
        #[pyo3(get)]
        pub length: u64,
        #[pyo3(get)]
        pub perms: u8,
        #[pyo3(get)]
        pub name: String,
    }

    m.add("PERM_NONE", lancelot::loader::Permissions::empty().bits())?;
    m.add("PERM_R", lancelot::loader::Permissions::R.bits())?;
    m.add("PERM_W", lancelot::loader::Permissions::W.bits())?;
    m.add("PERM_X", lancelot::loader::Permissions::X.bits())?;
    m.add("PERM_RW", lancelot::loader::Permissions::RW.bits())?;
    m.add("PERM_RX", lancelot::loader::Permissions::RX.bits())?;
    m.add("PERM_RWX", lancelot::loader::Permissions::RWX.bits())?;

    #[pymethods]
    impl PyWorkspace {
        #[getter]
        /// filename(self, /)
        /// --
        ///
        /// Fetch the filename.
        /// ```
        pub fn filename(&self) -> PyResult<String> {
            Ok(self.ws.filename.clone())
        }

        #[getter]
        /// loader(self, /)
        /// --
        ///
        /// Fetch the name of the loader used to create the workspace.
        pub fn loader(&self) -> PyResult<String> {
            Ok(self.ws.loader.get_name())
        }

        #[getter]
        /// base_address(self, /)
        /// --
        ///
        /// Fetch the base address to which the module was loaded.
        pub fn base_address(&self) -> PyResult<u64> {
            Ok(self.ws.module.base_address.into())
        }

        #[getter]
        pub fn sections(&self) -> PyResult<Vec<PySection>> {
            Ok(self.ws.module.sections.iter()
                .map(|section| PySection{
                    addr: section.addr.into(),
                    length: section.buf.len() as u64,
                    perms: section.perms.bits(),
                    name: section.name.clone(),
                })
                .collect())
        }

        /// probe(self, rva, length=1, /)
        /// --
        ///
        /// Is the given address mapped?
        pub fn probe(&self, rva: i64, length: Option<usize>) -> PyResult<bool> {
            match length {
                Some(length) => Ok(self.ws.probe(RVA::from(rva), length)),
                None =>  Ok(self.ws.probe(RVA::from(rva), 1)),
            }
        }
    }

    #[pyproto]
    impl pyo3::class::basic::PyObjectProtocol for PyWorkspace {
        fn __str__(&self) -> PyResult<String> {
            PyWorkspace::__repr__(self)
        }

        fn __repr__(&self) -> PyResult<String> {
            Ok(format!("PyWorkspace(filename: {} loader: {})",
                self.ws.filename.clone(),
                self.ws.loader.get_name(),
            ))
        }
    }

    #[pyproto]
    impl pyo3::class::basic::PyObjectProtocol for PySection {
        fn __str__(&self) -> PyResult<String> {
            PySection::__repr__(self)
        }

        fn __repr__(&self) -> PyResult<String> {
            Ok(format!("PySection(addr: {:#x} length: {:#x} perms: {:#x} name: {})",
                self.addr,
                self.length,
                self.perms,
                self.name,
            ))
        }
    }

    Ok(())
}

<commit_msg>pylancelot: implement read_bytes<commit_after>use pyo3;
use pyo3::types::{PyBytes};
use pyo3::prelude::*;

use lancelot::workspace;
use lancelot::arch::{RVA};

#[pymodule]
fn pylancelot(_py: Python, m: &PyModule) -> PyResult<()> {
    #[pyfn(m, "from_bytes")]
    /// from_bytes(filename, buf, /)
    /// --
    ///
    /// Create a workspace from the given bytes.
    ///
    /// Args:
    ///   filename (str): the source filename
    ///   buf (bytes): the bytes containing a PE, shellcode, etc.
    ///
    /// Raises:
    ///   ValueError: if failed to create the workspace. TODO: more specific.
    ///
    fn from_bytes(_py: Python, filename: String, buf: &PyBytes) -> PyResult<PyWorkspace> {
        let ws = match workspace::Workspace::from_bytes(&filename, buf.as_bytes()).load() {
            Err(_) => return Err(pyo3::exceptions::ValueError::py_err("failed to create workspace")),
            Ok(ws) => ws,
        };
        Ok(PyWorkspace{ws})
    }

    #[pyclass]
    pub struct PyWorkspace {
        ws: workspace::Workspace
    }

    #[pyclass]
    pub struct PySection {
        #[pyo3(get)]
        pub addr: i64,
        #[pyo3(get)]
        pub length: u64,
        #[pyo3(get)]
        pub perms: u8,
        #[pyo3(get)]
        pub name: String,
    }

    m.add("PERM_NONE", lancelot::loader::Permissions::empty().bits())?;
    m.add("PERM_R", lancelot::loader::Permissions::R.bits())?;
    m.add("PERM_W", lancelot::loader::Permissions::W.bits())?;
    m.add("PERM_X", lancelot::loader::Permissions::X.bits())?;
    m.add("PERM_RW", lancelot::loader::Permissions::RW.bits())?;
    m.add("PERM_RX", lancelot::loader::Permissions::RX.bits())?;
    m.add("PERM_RWX", lancelot::loader::Permissions::RWX.bits())?;

    #[pymethods]
    impl PyWorkspace {
        #[getter]
        /// filename(self, /)
        /// --
        ///
        /// Fetch the filename.
        /// ```
        pub fn filename(&self) -> PyResult<String> {
            Ok(self.ws.filename.clone())
        }

        #[getter]
        /// loader(self, /)
        /// --
        ///
        /// Fetch the name of the loader used to create the workspace.
        pub fn loader(&self) -> PyResult<String> {
            Ok(self.ws.loader.get_name())
        }

        #[getter]
        /// base_address(self, /)
        /// --
        ///
        /// Fetch the base address to which the module was loaded.
        pub fn base_address(&self) -> PyResult<u64> {
            Ok(self.ws.module.base_address.into())
        }

        #[getter]
        pub fn sections(&self) -> PyResult<Vec<PySection>> {
            Ok(self.ws.module.sections.iter()
                .map(|section| PySection{
                    addr: section.addr.into(),
                    length: section.buf.len() as u64,
                    perms: section.perms.bits(),
                    name: section.name.clone(),
                })
                .collect())
        }

        /// probe(self, rva, length=1, /)
        /// --
        ///
        /// Is the given address mapped?
        pub fn probe(&self, rva: i64, length: Option<usize>) -> PyResult<bool> {
            match length {
                Some(length) => Ok(self.ws.probe(RVA::from(rva), length)),
                None =>  Ok(self.ws.probe(RVA::from(rva), 1)),
            }
        }

        /// read_bytes(self, rva, length, /)
        /// --
        ///
        /// Read bytes from the given memory address.
        pub fn read_bytes<'p>(&self, py: Python<'p>, rva: i64, length: usize) -> PyResult<&'p pyo3::types::PyBytes> {
            match self.ws.read_bytes(RVA::from(rva), length) {
                Ok(buf) => {
                    Ok(pyo3::types::PyBytes::new(py, buf))
                },
                Err(e) => {
                    match e.downcast::<lancelot::workspace::WorkspaceError>() {
                        Ok(lancelot::workspace::WorkspaceError::InvalidAddress) => {
                            Err(pyo3::exceptions::LookupError::py_err("invalid address"))
                        },
                        Ok(lancelot::workspace::WorkspaceError::BufferOverrun) => {
                            Err(pyo3::exceptions::LookupError::py_err("buffer overrun"))
                        }
                        Ok(_) => {
                            Err(pyo3::exceptions::RuntimeError::py_err("unexpected error"))
                        },
                        Err(_) => {
                            Err(pyo3::exceptions::RuntimeError::py_err("unexpected error"))
                        },
                    }
                }
            }
        }
    }

    #[pyproto]
    impl pyo3::class::basic::PyObjectProtocol for PyWorkspace {
        fn __str__(&self) -> PyResult<String> {
            PyWorkspace::__repr__(self)
        }

        fn __repr__(&self) -> PyResult<String> {
            Ok(format!("PyWorkspace(filename: {} loader: {})",
                self.ws.filename.clone(),
                self.ws.loader.get_name(),
            ))
        }
    }

    #[pyproto]
    impl pyo3::class::basic::PyObjectProtocol for PySection {
        fn __str__(&self) -> PyResult<String> {
            PySection::__repr__(self)
        }

        fn __repr__(&self) -> PyResult<String> {
            Ok(format!("PySection(addr: {:#x} length: {:#x} perms: {:#x} name: {})",
                self.addr,
                self.length,
                self.perms,
                self.name,
            ))
        }
    }

    Ok(())
}

<|endoftext|>


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

//! State presets

/// Blending preset modes.
pub mod blend {
	use state::{Blend, BlendChannel, BlendValue, Equation, Factor};

    /// When combining two fragments, choose the source value
    pub const REPLACE: Blend = Blend {
        color: BlendChannel {
            equation: Equation::Add,
            source: Factor::One,
            destination: Factor::Zero,
        },
        alpha: BlendChannel {
            equation: Equation::Add,
            source: Factor::One,
            destination: Factor::Zero,
        }
    };

	/// When combining two fragments, add their values together, saturating at 1.0
	pub const ADD: Blend = Blend {
	    color: BlendChannel {
            equation: Equation::Add,
            source: Factor::One,
            destination: Factor::One,
        },
        alpha: BlendChannel {
            equation: Equation::Add,
            source: Factor::One,
            destination: Factor::One,
        },
    };

    /// When combining two fragments, multiply their values together.
    pub const MULTIPLY: Blend = Blend {
        color: BlendChannel {
            equation: Equation::Add,
            source: Factor::ZeroPlus(BlendValue::DestColor),
            destination: Factor::Zero,
        },
        alpha: BlendChannel {
            equation: Equation::Add,
            source: Factor::ZeroPlus(BlendValue::DestAlpha),
            destination: Factor::Zero,
        },
    };

    /// When combining two fragments, add the value of the source times its alpha channel with the
    /// value of the destination multiplied by the inverse of the source alpha channel. Has the
    /// usual transparency effect: mixes the two colors using a fraction of each one specified by
    /// the alpha of the source.
    pub const ALPHA: Blend = Blend {
        color: BlendChannel {
            equation: Equation::Add,
            source: Factor::ZeroPlus(BlendValue::SourceAlpha),
            destination: Factor::OneMinus(BlendValue::SourceAlpha),
        },
        alpha: BlendChannel {
            equation: Equation::Add,
            source: Factor::One,
            destination: Factor::One,
        },
    };

    /// When combining two fragments, subtract the destination color from a constant color
    /// using the source color as weight. Has an invert effect with the constant color
    /// as base and source color controlling displacement from the base color.
    /// A white source color and a white value results in plain invert.
    /// The output alpha is same as destination alpha.
    pub const INVERT: Blend = Blend {
        color: BlendChannel {
            equation: Equation::Sub,
            source: Factor::ZeroPlus(BlendValue::ConstColor),
            destination: Factor::ZeroPlus(BlendValue::SourceColor),
        },
        alpha: BlendChannel {
            equation: Equation::Add,
            source: Factor::Zero,
            destination: Factor::One,
        },
    };
}

/// Depth preset modes.
pub mod depth {
    use state::{Comparison, Depth};

    /// Always pass the depth test, no writes
    pub const PASS_TEST: Depth = Depth {
        fun: Comparison::Always,
        write: false,
    };

    /// "<=" comparison with read-only depth
    pub const LESS_EQUAL_TEST: Depth = Depth {
        fun: Comparison::LessEqual,
        write: false,
    };

    /// "<=" comparison with writable depth
    pub const LESS_EQUAL_WRITE: Depth = Depth {
        fun: Comparison::LessEqual,
        write: true,
    };
}
<commit_msg>Improve preset::depth docs (#44)<commit_after>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! State presets

/// Blending preset modes.
pub mod blend {
	use state::{Blend, BlendChannel, BlendValue, Equation, Factor};

    /// When combining two fragments, choose the source value
    pub const REPLACE: Blend = Blend {
        color: BlendChannel {
            equation: Equation::Add,
            source: Factor::One,
            destination: Factor::Zero,
        },
        alpha: BlendChannel {
            equation: Equation::Add,
            source: Factor::One,
            destination: Factor::Zero,
        }
    };

	/// When combining two fragments, add their values together, saturating at 1.0
	pub const ADD: Blend = Blend {
	    color: BlendChannel {
            equation: Equation::Add,
            source: Factor::One,
            destination: Factor::One,
        },
        alpha: BlendChannel {
            equation: Equation::Add,
            source: Factor::One,
            destination: Factor::One,
        },
    };

    /// When combining two fragments, multiply their values together.
    pub const MULTIPLY: Blend = Blend {
        color: BlendChannel {
            equation: Equation::Add,
            source: Factor::ZeroPlus(BlendValue::DestColor),
            destination: Factor::Zero,
        },
        alpha: BlendChannel {
            equation: Equation::Add,
            source: Factor::ZeroPlus(BlendValue::DestAlpha),
            destination: Factor::Zero,
        },
    };

    /// When combining two fragments, add the value of the source times its alpha channel with the
    /// value of the destination multiplied by the inverse of the source alpha channel. Has the
    /// usual transparency effect: mixes the two colors using a fraction of each one specified by
    /// the alpha of the source.
    pub const ALPHA: Blend = Blend {
        color: BlendChannel {
            equation: Equation::Add,
            source: Factor::ZeroPlus(BlendValue::SourceAlpha),
            destination: Factor::OneMinus(BlendValue::SourceAlpha),
        },
        alpha: BlendChannel {
            equation: Equation::Add,
            source: Factor::One,
            destination: Factor::One,
        },
    };

    /// When combining two fragments, subtract the destination color from a constant color
    /// using the source color as weight. Has an invert effect with the constant color
    /// as base and source color controlling displacement from the base color.
    /// A white source color and a white value results in plain invert.
    /// The output alpha is same as destination alpha.
    pub const INVERT: Blend = Blend {
        color: BlendChannel {
            equation: Equation::Sub,
            source: Factor::ZeroPlus(BlendValue::ConstColor),
            destination: Factor::ZeroPlus(BlendValue::SourceColor),
        },
        alpha: BlendChannel {
            equation: Equation::Add,
            source: Factor::Zero,
            destination: Factor::One,
        },
    };
}

/// [Depth](../../state/struct.Depth.html) presets for depth tests.
///
/// Depth testing is used to avoid drawing "further away" fragments on top of already drawn
/// fragments. Each fragment's output depth is tested against a depth buffer, if the test fails
/// the fragment will not be drawn.
///
/// A fragment's output depth is the interpolated vertex z-value, or otherwise
/// explicitly set (ie in OpenGL by *gl_FragDepth*).
pub mod depth {
    use state::{Comparison, Depth};

    /// When rendering a fragment, draw regardless of depth buffer state.
    /// Rendering will not update the depth buffer.
    pub const PASS_TEST: Depth = Depth {
        fun: Comparison::Always,
        write: false,
    };

    /// When rendering a fragment, only draw when the fragment's output depth **is less than or
    /// equal to** the current depth buffer value.
    /// Rendering will **not** update the depth buffer.
    pub const LESS_EQUAL_TEST: Depth = Depth {
        fun: Comparison::LessEqual,
        write: false,
    };

    /// When rendering a fragment, only draw when the fragment's output depth **is less than or
    /// equal to** the current depth buffer value.
    /// Rendering will update the depth buffer with the new depth value.
    pub const LESS_EQUAL_WRITE: Depth = Depth {
        fun: Comparison::LessEqual,
        write: true,
    };
}
<|endoftext|>


<commit_before>use std::iter::Peekable;
use std::str::Chars;

pub struct Reader<'s> {
    text: &'s str,

    line: usize,
    column: usize,
    offset: usize,

    cursor: Peekable<Chars<'s>>,
}

impl<'s> Reader<'s> {
    #[inline]
    pub fn new(text: &'s str) -> Reader<'s> {
        Reader {
            text: text,

            line: 1,
            column: 1,
            offset: 0,

            cursor: text.chars().peekable(),
        }
    }

    pub fn capture<F>(&mut self, block: F) -> Option<&str> where F: Fn(&mut Reader<'s>) {
        let start = self.offset;
        block(self);
        let end = self.offset;

        if end > start {
            Some(&self.text[start..end])
        } else {
            None
        }
    }

    #[inline]
    pub fn consume_any(&mut self, chars: &str) -> bool {
        self.consume_while(|c| chars.contains_char(c))
    }

    pub fn consume_char(&mut self, target: char) -> bool {
        match self.peek() {
            Some(c) if c == target => {
                self.next();
                true
            },
            _ => false,
        }
    }

    #[inline]
    pub fn consume_digits(&mut self) -> bool {
        self.consume_while(|c| c >= '0' && c <= '9')
    }

    pub fn consume_if<F>(&mut self, check: F) -> bool where F: Fn(char) -> bool {
        match self.peek() {
            Some(c) => {
                if check(c) {
                    self.next();
                    true
                } else {
                    false
                }
            },
            _ => false,
        }
    }

    /// http://www.w3.org/TR/REC-xml/#NT-Name
    pub fn consume_name(&mut self) -> bool {
        self.consume_name_start_char() && {
            while self.consume_name_char() {}
            true
        }
    }

    /// http://www.w3.org/TR/REC-xml/#NT-NameChar
    pub fn consume_name_char(&mut self) -> bool {
        self.consume_name_start_char() || self.consume_if(|c| {
            match c {
                '-' |
                '.' |
                '0'...'9' |
                '\u{B7}' |
                '\u{0300}'...'\u{036F}' |
                '\u{203F}'...'\u{2040}' => true,
                _ => false,
            }
        })
    }

    /// http://www.w3.org/TR/REC-xml/#NT-NameStartChar
    pub fn consume_name_start_char(&mut self) -> bool {
        self.consume_if(|c| {
            match c {
                ':' |
                'A'...'Z' |
                '_' |
                'a'...'z' |
                '\u{C0}'...'\u{D6}' |
                '\u{D8}'...'\u{F6}' |
                '\u{F8}'...'\u{2FF}' |
                '\u{370}'...'\u{37D}' |
                '\u{37F}'...'\u{1FFF}' |
                '\u{200C}'...'\u{200D}' |
                '\u{2070}'...'\u{218F}' |
                '\u{2C00}'...'\u{2FEF}' |
                '\u{3001}'...'\u{D7FF}' |
                '\u{F900}'...'\u{FDCF}' |
                '\u{FDF0}'...'\u{FFFD}' |
                '\u{10000}'...'\u{EFFFF}' => true,
                _ => false,
            }
        })
    }

    #[inline]
    pub fn consume_until_char(&mut self, target: char) -> bool {
        self.consume_while(|c| c != target)
    }

    pub fn consume_while<F>(&mut self, check: F) -> bool where F: Fn(char) -> bool {
        let mut consumed = false;
        while self.consume_if(|c| check(c)) {
            consumed = true;
        }
        consumed
    }

    /// http://www.w3.org/TR/REC-xml/#NT-S
    #[inline]
    pub fn consume_whitespace(&mut self) -> bool {
        self.consume_any("\x20\x09\x0D\x0A")
    }

    #[inline]
    pub fn peek(&mut self) -> Option<char> {
        self.cursor.peek().and_then(|&c| Some(c))
    }

    #[inline]
    pub fn position(&self) -> (usize, usize) {
        (self.line, self.column)
    }
}

impl<'s> Iterator for Reader<'s> {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some(c) => {
                if c == '\n' {
                    self.line += 1;
                    self.column = 1;
                } else {
                    self.column += 1;
                }
                self.offset += 1;
                Some(c)
            }
            _ => None,
        }
    }
}

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

    #[test]
    fn capture() {
        let mut reader = Reader::new("abcdefg");

        reader.consume_any("ab");
        let text = reader.capture(|reader| {
            reader.consume_any("cde");
        });

        assert_eq!(text.unwrap(), "cde");
    }

    #[test]
    fn consume_whitespace() {
        let mut reader = Reader::new(" \t  \n\n  \tm ");

        reader.consume_whitespace();

        assert_eq!(reader.line, 3);
        assert_eq!(reader.column, 4);
        assert_eq!(reader.offset, 9);
    }

    #[test]
    fn consume_name() {
        macro_rules! test(
            ($text:expr, $name:expr) => ({
                let mut reader = Reader::new($text);
                let name = reader.capture(|reader| {
                    reader.consume_name();
                });
                assert_eq!(name.unwrap(), $name);
            });
        );

        test!("foo", "foo");
        test!("foo bar", "foo");
        test!("foo42 bar", "foo42");
        test!("foo-bar baz", "foo-bar");
        test!("foo/", "foo");

        macro_rules! test(
            ($text:expr) => ({
                let mut reader = Reader::new($text);
                assert!(!reader.consume_name());
            });
        );

        test!(" foo");
        test!("!foo");
        test!("<foo");
        test!("?foo");
    }
}
<commit_msg>Move a test<commit_after>use std::iter::Peekable;
use std::str::Chars;

pub struct Reader<'s> {
    text: &'s str,

    line: usize,
    column: usize,
    offset: usize,

    cursor: Peekable<Chars<'s>>,
}

impl<'s> Reader<'s> {
    #[inline]
    pub fn new(text: &'s str) -> Reader<'s> {
        Reader {
            text: text,

            line: 1,
            column: 1,
            offset: 0,

            cursor: text.chars().peekable(),
        }
    }

    pub fn capture<F>(&mut self, block: F) -> Option<&str> where F: Fn(&mut Reader<'s>) {
        let start = self.offset;
        block(self);
        let end = self.offset;

        if end > start {
            Some(&self.text[start..end])
        } else {
            None
        }
    }

    #[inline]
    pub fn consume_any(&mut self, chars: &str) -> bool {
        self.consume_while(|c| chars.contains_char(c))
    }

    pub fn consume_char(&mut self, target: char) -> bool {
        match self.peek() {
            Some(c) if c == target => {
                self.next();
                true
            },
            _ => false,
        }
    }

    #[inline]
    pub fn consume_digits(&mut self) -> bool {
        self.consume_while(|c| c >= '0' && c <= '9')
    }

    pub fn consume_if<F>(&mut self, check: F) -> bool where F: Fn(char) -> bool {
        match self.peek() {
            Some(c) => {
                if check(c) {
                    self.next();
                    true
                } else {
                    false
                }
            },
            _ => false,
        }
    }

    /// http://www.w3.org/TR/REC-xml/#NT-Name
    pub fn consume_name(&mut self) -> bool {
        self.consume_name_start_char() && {
            while self.consume_name_char() {}
            true
        }
    }

    /// http://www.w3.org/TR/REC-xml/#NT-NameChar
    pub fn consume_name_char(&mut self) -> bool {
        self.consume_name_start_char() || self.consume_if(|c| {
            match c {
                '-' |
                '.' |
                '0'...'9' |
                '\u{B7}' |
                '\u{0300}'...'\u{036F}' |
                '\u{203F}'...'\u{2040}' => true,
                _ => false,
            }
        })
    }

    /// http://www.w3.org/TR/REC-xml/#NT-NameStartChar
    pub fn consume_name_start_char(&mut self) -> bool {
        self.consume_if(|c| {
            match c {
                ':' |
                'A'...'Z' |
                '_' |
                'a'...'z' |
                '\u{C0}'...'\u{D6}' |
                '\u{D8}'...'\u{F6}' |
                '\u{F8}'...'\u{2FF}' |
                '\u{370}'...'\u{37D}' |
                '\u{37F}'...'\u{1FFF}' |
                '\u{200C}'...'\u{200D}' |
                '\u{2070}'...'\u{218F}' |
                '\u{2C00}'...'\u{2FEF}' |
                '\u{3001}'...'\u{D7FF}' |
                '\u{F900}'...'\u{FDCF}' |
                '\u{FDF0}'...'\u{FFFD}' |
                '\u{10000}'...'\u{EFFFF}' => true,
                _ => false,
            }
        })
    }

    #[inline]
    pub fn consume_until_char(&mut self, target: char) -> bool {
        self.consume_while(|c| c != target)
    }

    pub fn consume_while<F>(&mut self, check: F) -> bool where F: Fn(char) -> bool {
        let mut consumed = false;
        while self.consume_if(|c| check(c)) {
            consumed = true;
        }
        consumed
    }

    /// http://www.w3.org/TR/REC-xml/#NT-S
    #[inline]
    pub fn consume_whitespace(&mut self) -> bool {
        self.consume_any("\x20\x09\x0D\x0A")
    }

    #[inline]
    pub fn peek(&mut self) -> Option<char> {
        self.cursor.peek().and_then(|&c| Some(c))
    }

    #[inline]
    pub fn position(&self) -> (usize, usize) {
        (self.line, self.column)
    }
}

impl<'s> Iterator for Reader<'s> {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some(c) => {
                if c == '\n' {
                    self.line += 1;
                    self.column = 1;
                } else {
                    self.column += 1;
                }
                self.offset += 1;
                Some(c)
            }
            _ => None,
        }
    }
}

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

    #[test]
    fn capture() {
        let mut reader = Reader::new("abcdefg");

        reader.consume_any("ab");
        let text = reader.capture(|reader| {
            reader.consume_any("cde");
        });

        assert_eq!(text.unwrap(), "cde");
    }

    #[test]
    fn consume_name() {
        macro_rules! test(
            ($text:expr, $name:expr) => ({
                let mut reader = Reader::new($text);
                let name = reader.capture(|reader| {
                    reader.consume_name();
                });
                assert_eq!(name.unwrap(), $name);
            });
        );

        test!("foo", "foo");
        test!("foo bar", "foo");
        test!("foo42 bar", "foo42");
        test!("foo-bar baz", "foo-bar");
        test!("foo/", "foo");

        macro_rules! test(
            ($text:expr) => ({
                let mut reader = Reader::new($text);
                assert!(!reader.consume_name());
            });
        );

        test!(" foo");
        test!("!foo");
        test!("<foo");
        test!("?foo");
    }

    #[test]
    fn consume_whitespace() {
        let mut reader = Reader::new(" \t  \n\n  \tm ");

        reader.consume_whitespace();

        assert_eq!(reader.line, 3);
        assert_eq!(reader.column, 4);
        assert_eq!(reader.offset, 9);
    }
}
<|endoftext|>


<commit_before>//! Implement record manupulation mechanisms.

use rustc_serialize::json;
use rustc_serialize::{Encodable, Encoder};
use rmp_serialize::encode;
use time::Tm;
use std::io;
use retry;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Record<T: Encodable> {
    tag: String,
    time: Tm,
    record: T,
}

pub enum FluentError {
    JsonEncodeError(json::EncoderError),
    MsgpackEncodeError(encode::Error),
    IOError(io::Error),
    RetryError(retry::RetryError),
}

impl From<io::Error> for FluentError {
    fn from(err: io::Error) -> FluentError {
        FluentError::IOError(err)
    }
}

impl From<encode::Error> for FluentError {
    fn from(err: encode::Error) -> FluentError {
        FluentError::MsgpackEncodeError(err)
    }
}

impl From<retry::RetryError> for FluentError {
    fn from(err: retry::RetryError) -> FluentError {
        FluentError::RetryError(err)
    }
}

impl From<json::EncoderError> for FluentError {
    fn from(err: json::EncoderError) -> FluentError {
        FluentError::JsonEncodeError(err)
    }
}

impl<T: Encodable> Record<T> {
    pub fn new(tag: String, time: Tm, record: T) -> Record<T> {
        Record {
            tag: tag,
            time: time,
            record: record,
        }
    }

    pub fn make_forwardable_json(self) -> Result<String, FluentError> {
        let message = try!(json::encode(&self));
        Ok(message)
    }
}

/// Construct custom encoding json style.
///
/// Because `Record` struct should map following style json:
///
/// `[tag, unixtime/eventtime, record]`
///
/// ref: https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v0#message-mode
impl<T: Encodable> Encodable for Record<T> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
        match *self {
            Record { tag: ref p_tag, time: ref p_time, record: ref p_record } => {
                encoder.emit_tuple(4, |encoder| {
                    try!(encoder.emit_tuple_arg(0, |encoder| p_tag.encode(encoder)));
                    try!(encoder.emit_tuple_arg(1, |encoder| {
                        p_time.to_timespec().sec.encode(encoder)
                    }));
                    try!(encoder.emit_tuple_arg(2, |encoder| p_record.encode(encoder)));
                    // Put `None::<T>` as-is for now.
                    try!(encoder.emit_tuple_arg(3, |encoder| None::<T>.encode(encoder)));
                    Ok(())
                })
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use time;
    use std::collections::HashMap;
    use rustc_serialize::json;
    use rustc_serialize::json::Json;

    #[test]
    fn test_json_format() {
        let tag = "fruently".to_string();
        let time = time::now();
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("name".to_string(), "fruently".to_string());
        let record = Record::new(tag.clone(), time, obj.clone());
        let forwardable_json = record.make_forwardable_json().ok().unwrap();
        let json_tag = json::encode(&tag.clone()).ok().unwrap();
        let json_obj = json::encode(&obj.clone()).ok().unwrap();
        let expected = format!("[{},{},{},{}]",
                               json_tag,
                               time.to_timespec().sec,
                               json_obj,
                               Json::Null);
        assert_eq!(expected, forwardable_json);
    }
}
<commit_msg>record: Fix rustdoc<commit_after>//! Implement record manupulation mechanisms.

use rustc_serialize::json;
use rustc_serialize::{Encodable, Encoder};
use rmp_serialize::encode;
use time::Tm;
use std::io;
use retry;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Record<T: Encodable> {
    tag: String,
    time: Tm,
    record: T,
}

pub enum FluentError {
    JsonEncodeError(json::EncoderError),
    MsgpackEncodeError(encode::Error),
    IOError(io::Error),
    RetryError(retry::RetryError),
}

impl From<io::Error> for FluentError {
    fn from(err: io::Error) -> FluentError {
        FluentError::IOError(err)
    }
}

impl From<encode::Error> for FluentError {
    fn from(err: encode::Error) -> FluentError {
        FluentError::MsgpackEncodeError(err)
    }
}

impl From<retry::RetryError> for FluentError {
    fn from(err: retry::RetryError) -> FluentError {
        FluentError::RetryError(err)
    }
}

impl From<json::EncoderError> for FluentError {
    fn from(err: json::EncoderError) -> FluentError {
        FluentError::JsonEncodeError(err)
    }
}

impl<T: Encodable> Record<T> {
    pub fn new(tag: String, time: Tm, record: T) -> Record<T> {
        Record {
            tag: tag,
            time: time,
            record: record,
        }
    }

    pub fn make_forwardable_json(self) -> Result<String, FluentError> {
        let message = try!(json::encode(&self));
        Ok(message)
    }
}

/// Construct custom encoding json/msgpack style.
///
/// Because `Record` struct should map following style json/msgpack:
///
/// `[tag, unixtime/eventtime, record]`
///
/// ref: https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v0#message-mode
impl<T: Encodable> Encodable for Record<T> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
        match *self {
            Record { tag: ref p_tag, time: ref p_time, record: ref p_record } => {
                encoder.emit_tuple(4, |encoder| {
                    try!(encoder.emit_tuple_arg(0, |encoder| p_tag.encode(encoder)));
                    try!(encoder.emit_tuple_arg(1, |encoder| {
                        p_time.to_timespec().sec.encode(encoder)
                    }));
                    try!(encoder.emit_tuple_arg(2, |encoder| p_record.encode(encoder)));
                    // Put `None::<T>` as-is for now.
                    try!(encoder.emit_tuple_arg(3, |encoder| None::<T>.encode(encoder)));
                    Ok(())
                })
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use time;
    use std::collections::HashMap;
    use rustc_serialize::json;
    use rustc_serialize::json::Json;

    #[test]
    fn test_json_format() {
        let tag = "fruently".to_string();
        let time = time::now();
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("name".to_string(), "fruently".to_string());
        let record = Record::new(tag.clone(), time, obj.clone());
        let forwardable_json = record.make_forwardable_json().ok().unwrap();
        let json_tag = json::encode(&tag.clone()).ok().unwrap();
        let json_obj = json::encode(&obj.clone()).ok().unwrap();
        let expected = format!("[{},{},{},{}]",
                               json_tag,
                               time.to_timespec().sec,
                               json_obj,
                               Json::Null);
        assert_eq!(expected, forwardable_json);
    }
}
<|endoftext|>


<commit_before>//! Test module for `cripes::util::graph::transform`, which provides utilities
//! for incremental construction and transformation of graphs.

use std::iter::{self, Iterator};

use cripes::util::graph::{Graph, ConcreteGraph, DirectedGraph,
                          WeightedGraph};
use cripes::util::graph::transform::{Builder, Target};

type G = WeightedGraph<(),char>;

#[derive(Clone, Debug)]
enum S {
    One(char),
    Seq(char, char)
}
impl From<char> for S {
    fn from(c: char) -> Self {
        S::One(c)
    }
}
#[derive(Clone, Debug)]
enum E {
    Single(S),
    Fork(S, S)
}
impl From<S> for E {
    fn from(c: S) -> Self {
        E::Single(c)
    }
}
impl From<(S, S)> for E {
    fn from(c: (S, S)) -> Self {
        E::Fork(c.0, c.1)
    }
}

fn target_node<E>(g: &mut G, _: &E) -> <G as Graph>::NodeId {
    g.add_node(())
}

fn build(ep: &mut Builder<G>,
         next: Target<<G as Graph>::NodeId>,
         input: E) -> <G as Graph>::NodeId {
    match input {
        E::Fork(a,b) => {
            let next = Target::Output(ep.recurse(next, a.into(), &build));
            ep.recurse(next, b.into(), &build);
            next.unwrap_id()
        },
        E::Single(conn) => {
            match conn {
                S::One(c) => ep.append_edge(next, c, target_node),
                S::Seq(a, b) => {
                    let mid = ep.append_edge(Target::AutoIntermediate, a, target_node);
                    ep.append_edge_from(mid, next, b, target_node)
                }
            }
        }
    }
}

/// Check that the `Builder` utility behaves as appropriate
#[test]
fn test_builder() {
    let mut g = G::new();
    let entry = g.add_node(());
    let mut ep = Builder::new(g, entry);

    // upon construction, `ep` should report one input and zero outputs:
    //
    // (0)
    //  I
    panic_unless_eq!(&[entry], ep.stage_inputs());
    assert_eq!(ep.stage_outputs(), &[]);

    // after appending an edge, there should be one input and one output:
    //
    // (0)→(1)
    //  I    O
    ep.append_edge(Target::AutoOutput, 'a', target_node);

    panic_unless_eq!(2, ep.graph().node_count(), "wrong node count");
    let n1 = ep.graph().node_ids().nth(1).unwrap();

    panic_unless_eq!(&[entry], ep.stage_inputs(), "unexpected inputs for stage");
    panic_unless_eq!(&[n1], ep.stage_outputs(), "unexpected outputs for stage");

    // after advancing, there should be one input and zero outputs:
    //
    // (0)→(1)
    //       I
    ep.advance();
    panic_unless_eq!(&[n1], ep.stage_inputs(), "incorrect inputs for stage");
    panic_unless_eq!(&[], ep.stage_outputs(), "incorrect outputs for stage");

    // after recursing, the inputs should remain unchanged:
    //
    //    a    b    c
    // (0)→(1)→(2)→(3)
    //       I         O
    //
    // B::build calls `advance` when handling a Seq item, but because
    // this call happens within the context of `recurse` the effects of the
    // call should be local to that context.
    ep.recurse(Target::AutoOutput, E::Single(S::Seq('b', 'c')),
               |b, tgt, input| {
                   let o = build(b, tgt, input);
                   println!("stage outputs: {:?}", b.stage_outputs());
                   o
               });
    println!("stage outputs: {:?}", ep.stage_outputs());
    panic_unless_eq!(4, ep.graph().node_count(), "wrong node count");
    let n2 = ep.graph().node_ids().nth(2).unwrap();
    let n3 = ep.graph().node_ids().nth(3).unwrap();

    panic_unless_eq!(&[n1], ep.stage_inputs(),  "incorrect inputs for stage");
    panic_unless_eq!(&[n3], ep.stage_outputs(), "incorrect outputs for stage");
    panic_unless_eq!(&[n2], ep.graph().direct_successors(n1).collect::<Vec<_>>().as_slice(),
                     "incorrect successors for node 1");

    // adding a fork here will call `recurse` twice -- but we expect no
    // additional output nodes because Builder re-uses the first output node
    // when possible:
    //
    //       ╭───────╮ d
    //       ├───────┤ e
    //    a  │ b    c ↓
    // (0)→(1)→(2)→(3)
    //       I         O
    build(&mut ep, Target::AutoOutput, E::Fork('d'.into(), 'e'.into()));
    panic_unless_eq!(4, ep.graph().node_count(), "wrong node count");
    panic_unless_eq!(&[n2, n3, n3], ep.graph().direct_successors(n1).collect::<Vec<_>>().as_slice(),
                     "incorrect successors for node 1");
    panic_unless_eq!(&[n1], ep.stage_inputs(), "incorrect inputs for stage");
    panic_unless_eq!(&[n3], ep.stage_outputs(), "incorrect outputs for stage");

}

/// Check that Builder::chain works as expected.
#[test]
fn test_builder_chain() {
    let mut g = G::new();
    let entry = g.add_node(());
    let mut b = Builder::new(g, entry);

    panic_unless_eq!(&[entry], b.stage_inputs());
    panic_unless_eq!(&[], b.stage_outputs());

    b.chain(Target::AutoOutput, iter::repeat(E::Single(S::One('a'))).take(3), &build);
    panic_unless_eq!(4, b.graph().node_count(), "Wrong number of nodes after chaining a transition");
    panic_unless_eq!(3, b.graph().edge_count(), "Wrong number of edges after chaining a transition");
    let n3 = b.graph().node_ids().nth(3).unwrap();
    panic_unless_eq!(&[entry], b.stage_inputs());
    panic_unless_eq!(&[n3], b.stage_outputs());

    b.advance();

    panic_unless_eq!(&[n3], b.stage_inputs());
    panic_unless_eq!(&[], b.stage_outputs());
}
<commit_msg>tests/util/graph/transform: use ConcreteGraphMut, not ConcreteGraph<commit_after>//! Test module for `cripes::util::graph::transform`, which provides utilities
//! for incremental construction and transformation of graphs.

use std::iter::{self, Iterator};

use cripes::util::graph::{Graph,
                          ConcreteGraphMut,
                          DirectedGraph,
                          WeightedGraph};
use cripes::util::graph::transform::{Builder, Target};

type G = WeightedGraph<(),char>;

#[derive(Clone, Debug)]
enum S {
    One(char),
    Seq(char, char)
}
impl From<char> for S {
    fn from(c: char) -> Self {
        S::One(c)
    }
}
#[derive(Clone, Debug)]
enum E {
    Single(S),
    Fork(S, S)
}
impl From<S> for E {
    fn from(c: S) -> Self {
        E::Single(c)
    }
}
impl From<(S, S)> for E {
    fn from(c: (S, S)) -> Self {
        E::Fork(c.0, c.1)
    }
}

fn target_node<E>(g: &mut G, _: &E) -> <G as Graph>::NodeId {
    g.add_node(())
}

fn build(ep: &mut Builder<G>,
         next: Target<<G as Graph>::NodeId>,
         input: E) -> <G as Graph>::NodeId {
    match input {
        E::Fork(a,b) => {
            let next = Target::Output(ep.recurse(next, a.into(), &build));
            ep.recurse(next, b.into(), &build);
            next.unwrap_id()
        },
        E::Single(conn) => {
            match conn {
                S::One(c) => ep.append_edge(next, c, target_node),
                S::Seq(a, b) => {
                    let mid = ep.append_edge(Target::AutoIntermediate, a, target_node);
                    ep.append_edge_from(mid, next, b, target_node)
                }
            }
        }
    }
}

/// Check that the `Builder` utility behaves as appropriate
#[test]
fn test_builder() {
    let mut g = G::new();
    let entry = g.add_node(());
    let mut ep = Builder::new(g, entry);

    // upon construction, `ep` should report one input and zero outputs:
    //
    // (0)
    //  I
    panic_unless_eq!(&[entry], ep.stage_inputs());
    assert_eq!(ep.stage_outputs(), &[]);

    // after appending an edge, there should be one input and one output:
    //
    // (0)→(1)
    //  I    O
    ep.append_edge(Target::AutoOutput, 'a', target_node);

    panic_unless_eq!(2, ep.graph().node_count(), "wrong node count");
    let n1 = ep.graph().node_ids().nth(1).unwrap();

    panic_unless_eq!(&[entry], ep.stage_inputs(), "unexpected inputs for stage");
    panic_unless_eq!(&[n1], ep.stage_outputs(), "unexpected outputs for stage");

    // after advancing, there should be one input and zero outputs:
    //
    // (0)→(1)
    //       I
    ep.advance();
    panic_unless_eq!(&[n1], ep.stage_inputs(), "incorrect inputs for stage");
    panic_unless_eq!(&[], ep.stage_outputs(), "incorrect outputs for stage");

    // after recursing, the inputs should remain unchanged:
    //
    //    a    b    c
    // (0)→(1)→(2)→(3)
    //       I         O
    //
    // B::build calls `advance` when handling a Seq item, but because
    // this call happens within the context of `recurse` the effects of the
    // call should be local to that context.
    ep.recurse(Target::AutoOutput, E::Single(S::Seq('b', 'c')),
               |b, tgt, input| {
                   let o = build(b, tgt, input);
                   println!("stage outputs: {:?}", b.stage_outputs());
                   o
               });
    println!("stage outputs: {:?}", ep.stage_outputs());
    panic_unless_eq!(4, ep.graph().node_count(), "wrong node count");
    let n2 = ep.graph().node_ids().nth(2).unwrap();
    let n3 = ep.graph().node_ids().nth(3).unwrap();

    panic_unless_eq!(&[n1], ep.stage_inputs(),  "incorrect inputs for stage");
    panic_unless_eq!(&[n3], ep.stage_outputs(), "incorrect outputs for stage");
    panic_unless_eq!(&[n2], ep.graph().direct_successors(n1).collect::<Vec<_>>().as_slice(),
                     "incorrect successors for node 1");

    // adding a fork here will call `recurse` twice -- but we expect no
    // additional output nodes because Builder re-uses the first output node
    // when possible:
    //
    //       ╭───────╮ d
    //       ├───────┤ e
    //    a  │ b    c ↓
    // (0)→(1)→(2)→(3)
    //       I         O
    build(&mut ep, Target::AutoOutput, E::Fork('d'.into(), 'e'.into()));
    panic_unless_eq!(4, ep.graph().node_count(), "wrong node count");
    panic_unless_eq!(&[n2, n3, n3], ep.graph().direct_successors(n1).collect::<Vec<_>>().as_slice(),
                     "incorrect successors for node 1");
    panic_unless_eq!(&[n1], ep.stage_inputs(), "incorrect inputs for stage");
    panic_unless_eq!(&[n3], ep.stage_outputs(), "incorrect outputs for stage");

}

/// Check that Builder::chain works as expected.
#[test]
fn test_builder_chain() {
    let mut g = G::new();
    let entry = g.add_node(());
    let mut b = Builder::new(g, entry);

    panic_unless_eq!(&[entry], b.stage_inputs());
    panic_unless_eq!(&[], b.stage_outputs());

    b.chain(Target::AutoOutput, iter::repeat(E::Single(S::One('a'))).take(3), &build);
    panic_unless_eq!(4, b.graph().node_count(), "Wrong number of nodes after chaining a transition");
    panic_unless_eq!(3, b.graph().edge_count(), "Wrong number of edges after chaining a transition");
    let n3 = b.graph().node_ids().nth(3).unwrap();
    panic_unless_eq!(&[entry], b.stage_inputs());
    panic_unless_eq!(&[n3], b.stage_outputs());

    b.advance();

    panic_unless_eq!(&[n3], b.stage_inputs());
    panic_unless_eq!(&[], b.stage_outputs());
}
<|endoftext|>


<commit_before>//! # runner
//!
//! Runs the requested tasks.

//! The flow is as follows:
//!
//! * Load env variables
//! * Create an execution plan based on the requested task and its dependencies
//! * Run all tasks defined in the execution plan
//!

#[cfg(test)]
#[path = "./runner_test.rs"]
mod runner_test;

use command;
use installer;
use log::Logger;
use std::collections::HashSet;
use std::time::SystemTime;
use types::{Config, ExecutionPlan, Step};

fn run_task(
    logger: &Logger,
    step: &Step,
) {
    logger.info::<()>("Running Task: ", &[&step.name], None);

    installer::install(&logger, &step.config);

    command::run(&logger, &step);
}

fn run_task_flow(
    logger: &Logger,
    execution_plan: &ExecutionPlan,
) {
    for step in &execution_plan.steps {
        run_task(&logger, &step);
    }
}

/// Returns the actual task name to invoke as tasks may have aliases
fn get_task_name(
    logger: &Logger,
    config: &Config,
    name: &str,
) -> String {
    match config.tasks.get(name) {
        Some(task_config) => {
            let alias = task_config.get_alias();

            match alias {
                Some(ref alias) => get_task_name(logger, config, alias),
                _ => name.to_string(),
            }
        }
        None => {
            // This will actually panic
            logger.error::<()>("Task not found: ", &[&name], None);

            name.to_string()
        }
    }
}

/// Creates an execution plan for the given step based on existing execution plan data
fn create_execution_plan_for_step(
    logger: &Logger,
    config: &Config,
    task: &str,
    steps: &mut Vec<Step>,
    task_names: &mut HashSet<String>,
    root: bool,
) {
    let actual_task = get_task_name(logger, config, task);

    match config.tasks.get(&actual_task) {
        Some(task_config) => {
            match task_config.dependencies {
                Some(ref dependencies) => {
                    for dependency in dependencies {
                        create_execution_plan_for_step(&logger, &config, &dependency, steps, task_names, false);
                    }
                }
                _ => logger.verbose::<()>("No dependencies found for task: ", &[&task], None),
            };

            if !task_names.contains(task) {
                let mut clone_task = task_config.clone();
                let normalized_task = clone_task.get_normalized_task();
                let add = !normalized_task.disabled.unwrap_or(false);

                if add {
                    steps.push(Step { name: task.to_string(), config: normalized_task });
                    task_names.insert(task.to_string());
                }
            } else if root {
                logger.error::<()>("Circular reference found for task: ", &[&task], None);
            }
        }
        None => logger.error::<()>("Task not found: ", &[&task], None),
    }
}

/// Creates the full execution plan
fn create_execution_plan(
    logger: &Logger,
    config: &Config,
    task: &str,
) -> ExecutionPlan {
    let mut task_names = HashSet::new();
    let mut steps = Vec::new();

    match config.config.init_task {
        Some(ref task) => {
            match config.tasks.get(task) {
                Some(task_config) => {
                    let mut clone_task = task_config.clone();
                    let normalized_task = clone_task.get_normalized_task();
                    let add = !normalized_task.disabled.unwrap_or(false);

                    if add {
                        steps.push(Step { name: task.to_string(), config: normalized_task });
                    }
                }
                None => logger.error::<()>("Task not found: ", &[task], None),
            }
        }
        None => logger.verbose::<()>("Init task not defined.", &[], None),
    };

    create_execution_plan_for_step(&logger, &config, &task, &mut steps, &mut task_names, true);

    // always add end task even if already executed due to some depedency
    match config.config.end_task {
        Some(ref task) => {
            match config.tasks.get(task) {
                Some(task_config) => {
                    let mut clone_task = task_config.clone();
                    let normalized_task = clone_task.get_normalized_task();
                    let add = !normalized_task.disabled.unwrap_or(false);

                    if add {
                        steps.push(Step { name: task.to_string(), config: normalized_task });
                    }
                }
                None => logger.error::<()>("Task not found: ", &[task], None),
            }
        }
        None => logger.verbose::<()>("End task not defined.", &[], None),
    };

    ExecutionPlan { steps }
}

/// Runs the requested tasks.

/// The flow is as follows:
///
/// * Create an execution plan based on the requested task and its dependencies
/// * Run all tasks defined in the execution plan
pub fn run(
    logger: &Logger,
    config: &Config,
    task: &str,
) {
    let start_time = SystemTime::now();

    let execution_plan = create_execution_plan(&logger, &config, &task);
    logger.verbose("Created execution plan: ", &[], Some(&execution_plan));

    run_task_flow(logger, &execution_plan);

    let time_string = match start_time.elapsed() {
        Ok(elapsed) => {
            let mut string = " in ".to_string();
            string.push_str(&elapsed.as_secs().to_string());
            string.push_str(" seconds");

            string
        }
        _ => "".to_string(),
    };

    logger.info::<()>("Build Done", &[&time_string, "."], None);
}

/// Only prints the execution plan
pub fn print(
    logger: &Logger,
    config: &Config,
    task: &str,
) {
    let execution_plan = create_execution_plan(&logger, &config, &task);
    logger.verbose("Created execution plan: ", &[], Some(&execution_plan));

    println!("{:#?}", &execution_plan);
}
<commit_msg>initial work on workspace support<commit_after>//! # runner
//!
//! Runs the requested tasks.

//! The flow is as follows:
//!
//! * Load env variables
//! * Create an execution plan based on the requested task and its dependencies
//! * Run all tasks defined in the execution plan
//!

#[cfg(test)]
#[path = "./runner_test.rs"]
mod runner_test;

use command;
use installer;
use log::Logger;
use std::collections::HashSet;
use std::time::SystemTime;
use types::{Config, CrateInfo, ExecutionPlan, Step, Task};

fn run_task(
    logger: &Logger,
    step: &Step,
) {
    logger.info::<()>("Running Task: ", &[&step.name], None);

    installer::install(&logger, &step.config);

    command::run(&logger, &step);
}

fn run_task_flow(
    logger: &Logger,
    execution_plan: &ExecutionPlan,
) {
    for step in &execution_plan.steps {
        run_task(&logger, &step);
    }
}

/// Returns the actual task name to invoke as tasks may have aliases
fn get_task_name(
    logger: &Logger,
    config: &Config,
    name: &str,
) -> String {
    match config.tasks.get(name) {
        Some(task_config) => {
            let alias = task_config.get_alias();

            match alias {
                Some(ref alias) => get_task_name(logger, config, alias),
                _ => name.to_string(),
            }
        }
        None => {
            // This will actually panic
            logger.error::<()>("Task not found: ", &[&name], None);

            name.to_string()
        }
    }
}

/// Creates an execution plan for the given step based on existing execution plan data
fn create_execution_plan_for_step(
    logger: &Logger,
    config: &Config,
    task: &str,
    steps: &mut Vec<Step>,
    task_names: &mut HashSet<String>,
    root: bool,
) {
    let actual_task = get_task_name(logger, config, task);

    match config.tasks.get(&actual_task) {
        Some(task_config) => {
            match task_config.dependencies {
                Some(ref dependencies) => {
                    for dependency in dependencies {
                        create_execution_plan_for_step(&logger, &config, &dependency, steps, task_names, false);
                    }
                }
                _ => logger.verbose::<()>("No dependencies found for task: ", &[&task], None),
            };

            if !task_names.contains(task) {
                let mut clone_task = task_config.clone();
                let normalized_task = clone_task.get_normalized_task();
                let add = !normalized_task.disabled.unwrap_or(false);

                if add {
                    steps.push(Step { name: task.to_string(), config: normalized_task });
                    task_names.insert(task.to_string());
                }
            } else if root {
                logger.error::<()>("Circular reference found for task: ", &[&task], None);
            }
        }
        None => logger.error::<()>("Task not found: ", &[&task], None),
    }
}

/// Creates the full execution plan
fn create_execution_plan(
    logger: &Logger,
    config: &Config,
    task: &str,
) -> ExecutionPlan {
    let mut task_names = HashSet::new();
    let mut steps = Vec::new();

    match config.config.init_task {
        Some(ref task) => {
            match config.tasks.get(task) {
                Some(task_config) => {
                    let mut clone_task = task_config.clone();
                    let normalized_task = clone_task.get_normalized_task();
                    let add = !normalized_task.disabled.unwrap_or(false);

                    if add {
                        steps.push(Step { name: task.to_string(), config: normalized_task });
                    }
                }
                None => logger.error::<()>("Task not found: ", &[task], None),
            }
        }
        None => logger.verbose::<()>("Init task not defined.", &[], None),
    };

    // load crate info and look for workspace info
    let crate_info = CrateInfo::load(&logger);

    if crate_info.workspace.is_some() {
        let workspace = crate_info.workspace.unwrap();
        let members = workspace.members.unwrap_or(vec![]);

        let mut script_lines = vec![];
        for member in &members {
            let mut cd_line = "cd ".to_string();
            cd_line.push_str(&member);
            script_lines.push(cd_line);

            let mut make_line = "cargo make ".to_string();
            make_line.push_str(&task);
            script_lines.push(make_line);

            script_lines.push("cd ..".to_string());
        }

        let mut workspace_task = Task::new();
        workspace_task.script = Some(script_lines);

        steps.push(Step { name: "workspace".to_string(), config: workspace_task });
    } else {
        create_execution_plan_for_step(&logger, &config, &task, &mut steps, &mut task_names, true);
    }

    // always add end task even if already executed due to some depedency
    match config.config.end_task {
        Some(ref task) => {
            match config.tasks.get(task) {
                Some(task_config) => {
                    let mut clone_task = task_config.clone();
                    let normalized_task = clone_task.get_normalized_task();
                    let add = !normalized_task.disabled.unwrap_or(false);

                    if add {
                        steps.push(Step { name: task.to_string(), config: normalized_task });
                    }
                }
                None => logger.error::<()>("Task not found: ", &[task], None),
            }
        }
        None => logger.verbose::<()>("End task not defined.", &[], None),
    };

    ExecutionPlan { steps }
}

/// Runs the requested tasks.

/// The flow is as follows:
///
/// * Create an execution plan based on the requested task and its dependencies
/// * Run all tasks defined in the execution plan
pub fn run(
    logger: &Logger,
    config: &Config,
    task: &str,
) {
    let start_time = SystemTime::now();

    let execution_plan = create_execution_plan(&logger, &config, &task);
    logger.verbose("Created execution plan: ", &[], Some(&execution_plan));

    run_task_flow(logger, &execution_plan);

    let time_string = match start_time.elapsed() {
        Ok(elapsed) => {
            let mut string = " in ".to_string();
            string.push_str(&elapsed.as_secs().to_string());
            string.push_str(" seconds");

            string
        }
        _ => "".to_string(),
    };

    logger.info::<()>("Build Done", &[&time_string, "."], None);
}

/// Only prints the execution plan
pub fn print(
    logger: &Logger,
    config: &Config,
    task: &str,
) {
    let execution_plan = create_execution_plan(&logger, &config, &task);
    logger.verbose("Created execution plan: ", &[], Some(&execution_plan));

    println!("{:#?}", &execution_plan);
}
<|endoftext|>


<commit_before>// Claxon -- A FLAC decoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License, version 3,
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::cmp::Eq;
use std::ops::{Add, BitAnd, BitOr, Neg, Shl, Shr, Sub};

/// An trait that allows for interegers to be generic in width.
pub trait Sample: Copy + Clone + Eq +
    Neg<Output = Self> +
    Add<Output = Self> +
    Sub<Output = Self> +
    Shl<usize, Output = Self> +
    Shr<usize, Output = Self> +
    BitOr<Self, Output = Self> +
    BitAnd<Self, Output = Self> {

    type Unsigned: BitAnd<<Self as Sample>::Unsigned,
                          Output = <Self as Sample>::Unsigned>
                 + BitOr<Output = <Self as Sample>::Unsigned>
                 + Shl<usize, Output = <Self as Sample>::Unsigned>
                 + Shr<usize, Output = <Self as Sample>::Unsigned>
                 + Add<Output = <Self as Sample>::Unsigned>
                 + Eq + Copy + Clone;

    /// Returns the maximal value that the type can contain.
    // TODO: is this actually required, can we do without in non-debug versions?
    fn max() -> Self;

    /// Returns the minimal value that the type can contain.
    // TODO: is this actually required, can we do without in non-debug versions?
    fn min() -> Self;

    /// Returns the maximal value that the `Unsigned` type can contain.
    // TODO: is this actually required, can we do without in non-debug versions?
    fn max_unsigned() -> <Self as Sample>::Unsigned;

    /// Returns 0.
    // TODO: could be an associated constant once those land.
    fn zero() -> Self;

    /// Returns 1.
    // TODO: could be an associated constant once those land.
    fn one() -> Self;

    /// Returns 0 as the unsigned type.
    // TODO: could be an associated constant once those land.
    fn zero_unsigned() -> <Self as Sample>::Unsigned;

    /// Returns 1 as the unsigned type.
    // TODO: could be an associated constant once those land.
    fn one_unsigned() -> <Self as Sample>::Unsigned;

    /// Interprets the unsigned value as a signed number.
    fn from_unsigned(unsigned: <Self as Sample>::Unsigned) -> Self;

    /// Converts an `u16` to the unsigned sample, assuming it will not overflow.
    fn from_u16_nofail(x: u16) -> <Self as Sample>::Unsigned;

    /// Converts an `i32` to the sample, assuming it will not overflow.
    fn from_i32_nofail(x: i32) -> Self;

    /// Converts an `i32` to the sample, returning `None` on overflow.
    fn from_i32(x: i32) -> Option<Self>;

    /// Adds with wraparound on overflow.
    fn wrapping_add(self, other: Self) -> Self;

    /// Subtracts with wraparound on overflow.
    fn wrapping_sub(self, other: Self) -> Self;
}

macro_rules! impl_sample {
    ($signed: ident, $unsigned: ident) => {
        impl Sample for $signed {

            type Unsigned = $unsigned;

            fn max() -> $signed {
                use std::$signed;
                $signed::MAX
            }

            fn min() -> $signed {
                use std::$signed;
                $signed::MIN
            }

            fn max_unsigned() -> $unsigned {
                use std::$unsigned;
                $unsigned::MAX
            }

            fn zero() -> $signed {
                0
            }

            fn one() -> $signed {
                1
            }

            fn zero_unsigned() -> $unsigned {
                0
            }

            fn one_unsigned() -> $unsigned {
                1
            }

            fn from_unsigned(unsigned: $unsigned) -> $signed {
                unsigned as $signed
            }

            fn from_u16_nofail(x: u16) -> $unsigned {
                x as $unsigned
            }

            fn from_i32_nofail(x: i32) -> $signed {
                x as $signed
            }

            fn from_i32(x: i32) -> Option<$signed> {
                use std::$signed;
                if x > $signed::MAX || x < $signed::MIN {
                    None
                } else {
                    x as $signed
                }
            }

            fn wrapping_add(self, other: $signed) -> $signed {
                self.wrapping_add(other)
            }

            fn wrapping_sub(self, other: $signed) -> $signed {
                self.wrapping_sub(other)
            }
        }
    };
}

impl_sample!(i8, u8);
impl_sample!(i16, u16);
impl_sample!(i32, u32);
<commit_msg>add from_i64 method to Sample<commit_after>// Claxon -- A FLAC decoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License, version 3,
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::cmp::Eq;
use std::ops::{Add, BitAnd, BitOr, Neg, Shl, Shr, Sub};

/// An trait that allows for interegers to be generic in width.
pub trait Sample: Copy + Clone + Eq +
    Neg<Output = Self> +
    Add<Output = Self> +
    Sub<Output = Self> +
    Shl<usize, Output = Self> +
    Shr<usize, Output = Self> +
    BitOr<Self, Output = Self> +
    BitAnd<Self, Output = Self> {

    type Unsigned: BitAnd<<Self as Sample>::Unsigned,
                          Output = <Self as Sample>::Unsigned>
                 + BitOr<Output = <Self as Sample>::Unsigned>
                 + Shl<usize, Output = <Self as Sample>::Unsigned>
                 + Shr<usize, Output = <Self as Sample>::Unsigned>
                 + Add<Output = <Self as Sample>::Unsigned>
                 + Eq + Copy + Clone;

    /// Returns the maximal value that the type can contain.
    // TODO: is this actually required, can we do without in non-debug versions?
    fn max() -> Self;

    /// Returns the minimal value that the type can contain.
    // TODO: is this actually required, can we do without in non-debug versions?
    fn min() -> Self;

    /// Returns the maximal value that the `Unsigned` type can contain.
    // TODO: is this actually required, can we do without in non-debug versions?
    fn max_unsigned() -> <Self as Sample>::Unsigned;

    /// Returns 0.
    // TODO: could be an associated constant once those land.
    fn zero() -> Self;

    /// Returns 1.
    // TODO: could be an associated constant once those land.
    fn one() -> Self;

    /// Returns 0 as the unsigned type.
    // TODO: could be an associated constant once those land.
    fn zero_unsigned() -> <Self as Sample>::Unsigned;

    /// Returns 1 as the unsigned type.
    // TODO: could be an associated constant once those land.
    fn one_unsigned() -> <Self as Sample>::Unsigned;

    /// Interprets the unsigned value as a signed number.
    fn from_unsigned(unsigned: <Self as Sample>::Unsigned) -> Self;

    /// Converts an `u16` to the unsigned sample, assuming it will not overflow.
    fn from_u16_nofail(x: u16) -> <Self as Sample>::Unsigned;

    /// Converts an `i32` to the sample, assuming it will not overflow.
    fn from_i32_nofail(x: i32) -> Self;

    /// Converts an `i32` to the sample, returning `None` on overflow.
    fn from_i32(x: i32) -> Option<Self>;

    /// Converts an `i64` to the sample, returning `None` on overflow.
    fn from_i64(x: i64) -> Option<Self>;

    /// Adds with wraparound on overflow.
    fn wrapping_add(self, other: Self) -> Self;

    /// Subtracts with wraparound on overflow.
    fn wrapping_sub(self, other: Self) -> Self;
}

macro_rules! impl_sample {
    ($signed: ident, $unsigned: ident) => {
        impl Sample for $signed {

            type Unsigned = $unsigned;

            fn max() -> $signed {
                use std::$signed;
                $signed::MAX
            }

            fn min() -> $signed {
                use std::$signed;
                $signed::MIN
            }

            fn max_unsigned() -> $unsigned {
                use std::$unsigned;
                $unsigned::MAX
            }

            fn zero() -> $signed {
                0
            }

            fn one() -> $signed {
                1
            }

            fn zero_unsigned() -> $unsigned {
                0
            }

            fn one_unsigned() -> $unsigned {
                1
            }

            fn from_unsigned(unsigned: $unsigned) -> $signed {
                unsigned as $signed
            }

            fn from_u16_nofail(x: u16) -> $unsigned {
                x as $unsigned
            }

            fn from_i32_nofail(x: i32) -> $signed {
                x as $signed
            }

            fn from_i32(x: i32) -> Option<$signed> {
                use std::$signed;
                if x > $signed::MAX || x < $signed::MIN {
                    None
                } else {
                    x as $signed
                }
            }

            fn from_i64(x: i64) -> Option<$signed> {
                use std::$signed;
                if x > $signed::MAX || x < $signed::MIN {
                    None
                } else {
                    x as $signed
                }
            }

            fn wrapping_add(self, other: $signed) -> $signed {
                self.wrapping_add(other)
            }

            fn wrapping_sub(self, other: $signed) -> $signed {
                self.wrapping_sub(other)
            }
        }
    };
}

impl_sample!(i8, u8);
impl_sample!(i16, u16);
impl_sample!(i32, u32);
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

/// top level document
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Spec {
    /// version string
    pub swagger: String,
    pub info: Info,
    #[serde(skip_serializing_if="Option::is_none")]
    pub host: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="basePath")]
    pub base_path: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub schemes: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub consumes: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub produces: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub tags: Option<Vec<Tag>>,
    /// HTTP path to Operations mappings
    pub paths: BTreeMap<String, Operations>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub definitions: Option<BTreeMap<String, Schema>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub parameters: Option<BTreeMap<String, Parameter>>,
    /// mappings to http response codes or "default"
    #[serde(skip_serializing_if="Option::is_none")]
    pub responses: Option<BTreeMap<String, Response>>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="securityDefinitions")]
    pub security_definitions: Option<BTreeMap<String, Security>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Tag {
    pub name: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="externalDocs")]
    pub external_docs: Option<Vec<ExternalDoc>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct ExternalDoc {
    pub url: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub description: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Info {
    #[serde(skip_serializing_if="Option::is_none")]
    pub title: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="termsOfService")]
    pub terms_of_service: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub contact: Option<Contact>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub license: Option<License>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub version: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Contact {
    #[serde(skip_serializing_if="Option::is_none")]
    pub name: Option<String>,
    // TODO: Make sure the url is a valid URL
    #[serde(skip_serializing_if="Option::is_none")]
    pub url: Option<String>,
    // TODO: Make sure the email is a valid email
    #[serde(skip_serializing_if="Option::is_none")]
    pub email: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct License {
    #[serde(skip_serializing_if="Option::is_none")]
    pub name: Option<String>,
    // TODO: Make sure the url is a valid URL
    #[serde(skip_serializing_if="Option::is_none")]
    pub url: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Operations {
    #[serde(skip_serializing_if="Option::is_none")]
    pub get: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub post: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub put: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub patch: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub delete: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub options: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub head: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub parameters: Option<Vec<ParameterOrRef>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Operation {
    #[serde(skip_serializing_if="Option::is_none")]
    pub summary: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub consumes: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub produces: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub schemes: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub tags: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="operationId")]
    pub operation_id: Option<String>,
    pub responses: BTreeMap<String, Response>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub parameters: Option<Vec<ParameterOrRef>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Parameter {
    pub name: String,
    #[serde(rename="in")]
    pub location: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub required: Option<bool>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub schema: Option<Schema>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="uniqueItems")]
    pub unique_items: Option<bool>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="type")]
    pub param_type: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub format: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub description: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Response {
    pub description: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub schema: Option<Schema>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
pub enum ParameterOrRef {
    #[derive(Default)]
    Parameter {
        name: String,
        #[serde(rename="in")]
        location: String,
        #[serde(skip_serializing_if="Option::is_none")]
        required: Option<bool>,
        #[serde(skip_serializing_if="Option::is_none")]
        schema: Option<Schema>,
        #[serde(skip_serializing_if="Option::is_none")]
        #[serde(rename="uniqueItems")]
        unique_items: Option<bool>,
        #[serde(skip_serializing_if="Option::is_none")]
        #[serde(rename="type")]
        param_type: Option<String>,
        #[serde(skip_serializing_if="Option::is_none")]
        format: Option<String>,
        #[serde(skip_serializing_if="Option::is_none")]
        description: Option<String>,
    },
    Ref {
        #[serde(rename="$ref")]
        ref_path: String,
    },
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(tag = "type")]
pub enum Security {
    #[serde(rename="apiKey")]
    ApiKey {
        name: String,
        #[serde(rename="in")]
        location: String,
    },
    #[serde(rename="oauth2")]
    Oauth2 {
        flow: String,
        #[serde(rename="authorizationUrl")]
        authorization_url: String,
        #[serde(rename="tokenUrl")]
        #[serde(skip_serializing_if="Option::is_none")]
        token_url: Option<String>,
        scopes: BTreeMap<String, String>,
    },
    #[serde(rename="basic")]
    Basic,
}

/// A [JSON schema](http://json-schema.org/) definition describing
/// the shape and properties of an object.
///
/// This may also contain a `$ref` to another definition
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Schema {
    #[serde(skip_serializing_if="Option::is_none")]
    /// a [JSON reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03)
    /// path to another defintion
    #[serde(rename="$ref")]
    pub ref_path: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="type")]
    pub schema_type: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub format: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="enum")]
    pub enum_values: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub required: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub items: Option<Box<Schema>>,
    // implies object
    #[serde(skip_serializing_if="Option::is_none")]
    pub properties: Option<BTreeMap<String, Schema>>,
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json;
    use serde_yaml;
    use std::collections::BTreeMap;

    #[test]
    fn security_api_deserializes() {
        let json = r#"{"type":"apiKey", "name":"foo", "in": "query"}"#;
        assert_eq!(
            serde_yaml::from_str::<Security>(&json).unwrap(),
            Security::ApiKey {
                name: "foo".into(),
                location: "query".into(),
            }
        );
    }

    #[test]
    fn security_api_serializes() {
        let json = r#"{"type":"apiKey","name":"foo","in":"query"}"#;
        assert_eq!(
            serde_json::to_string(
                &Security::ApiKey {
                     name: "foo".into(),
                     location: "query".into(),
                 },
            )
                    .unwrap(),
            json
        );
    }

    #[test]
    fn security_basic_deserializes() {
        let json = r#"{"type":"basic"}"#;
        assert_eq!(
            serde_yaml::from_str::<Security>(&json).unwrap(),
            Security::Basic
        );
    }

    #[test]
    fn security_basic_serializes() {
        let json = r#"{"type":"basic"}"#;
        assert_eq!(json, serde_json::to_string(&Security::Basic).unwrap());
    }

    #[test]
    fn security_oauth_deserializes() {
        let json = r#"{"type":"oauth2","flow":"implicit","authorizationUrl":"foo/bar","scopes":{"foo":"bar"}}"#;
        let mut scopes = BTreeMap::new();
        scopes.insert("foo".into(), "bar".into());
        assert_eq!(
            serde_yaml::from_str::<Security>(&json).unwrap(),
            Security::Oauth2 {
                flow: "implicit".into(),
                authorization_url: "foo/bar".into(),
                token_url: None,
                scopes: scopes,
            }
        );
    }

    #[test]
    fn security_oauth_serializes() {
        let json = r#"{"type":"oauth2","flow":"implicit","authorizationUrl":"foo/bar","scopes":{"foo":"bar"}}"#;
        let mut scopes = BTreeMap::new();
        scopes.insert("foo".into(), "bar".into());
        assert_eq!(
            json,
            serde_json::to_string(
                &Security::Oauth2 {
                     flow: "implicit".into(),
                     authorization_url: "foo/bar".into(),
                     token_url: None,
                     scopes: scopes,
                 },
            )
                    .unwrap()
        );
    }

    #[test]
    fn parameter_or_ref_deserializes_ref() {
        let json = r#"{"$ref":"foo/bar"}"#;
        assert_eq!(
            serde_yaml::from_str::<ParameterOrRef>(&json).unwrap(),
            ParameterOrRef::Ref { ref_path: "foo/bar".into() }
        );
    }

    #[test]
    fn parameter_or_ref_serializes_pref() {
        let json = r#"{"$ref":"foo/bar"}"#;
        assert_eq!(
            json,
            serde_json::to_string(&ParameterOrRef::Ref { ref_path: "foo/bar".into() }).unwrap()
        );
    }
}
<commit_msg>Add Security Requirements to Spec<commit_after>use std::collections::BTreeMap;

/// top level document
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Spec {
    /// version string
    pub swagger: String,
    pub info: Info,
    #[serde(skip_serializing_if="Option::is_none")]
    pub host: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="basePath")]
    pub base_path: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub schemes: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub consumes: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub produces: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub tags: Option<Vec<Tag>>,
    /// HTTP path to Operations mappings
    pub paths: BTreeMap<String, Operations>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub definitions: Option<BTreeMap<String, Schema>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub parameters: Option<BTreeMap<String, Parameter>>,
    /// mappings to http response codes or "default"
    #[serde(skip_serializing_if="Option::is_none")]
    pub responses: Option<BTreeMap<String, Response>>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="securityDefinitions")]
    pub security_definitions: Option<BTreeMap<String, Security>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub security: Option<Vec<BTreeMap<String, Vec<String>>>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Tag {
    pub name: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="externalDocs")]
    pub external_docs: Option<Vec<ExternalDoc>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct ExternalDoc {
    pub url: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub description: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Info {
    #[serde(skip_serializing_if="Option::is_none")]
    pub title: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="termsOfService")]
    pub terms_of_service: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub contact: Option<Contact>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub license: Option<License>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub version: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Contact {
    #[serde(skip_serializing_if="Option::is_none")]
    pub name: Option<String>,
    // TODO: Make sure the url is a valid URL
    #[serde(skip_serializing_if="Option::is_none")]
    pub url: Option<String>,
    // TODO: Make sure the email is a valid email
    #[serde(skip_serializing_if="Option::is_none")]
    pub email: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct License {
    #[serde(skip_serializing_if="Option::is_none")]
    pub name: Option<String>,
    // TODO: Make sure the url is a valid URL
    #[serde(skip_serializing_if="Option::is_none")]
    pub url: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Operations {
    #[serde(skip_serializing_if="Option::is_none")]
    pub get: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub post: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub put: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub patch: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub delete: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub options: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub head: Option<Operation>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub parameters: Option<Vec<ParameterOrRef>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Operation {
    #[serde(skip_serializing_if="Option::is_none")]
    pub summary: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub consumes: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub produces: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub schemes: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub tags: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="operationId")]
    pub operation_id: Option<String>,
    pub responses: BTreeMap<String, Response>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub parameters: Option<Vec<ParameterOrRef>>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Parameter {
    pub name: String,
    #[serde(rename="in")]
    pub location: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub required: Option<bool>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub schema: Option<Schema>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="uniqueItems")]
    pub unique_items: Option<bool>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="type")]
    pub param_type: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub format: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub description: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Response {
    pub description: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub schema: Option<Schema>,
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
pub enum ParameterOrRef {
    #[derive(Default)]
    Parameter {
        name: String,
        #[serde(rename="in")]
        location: String,
        #[serde(skip_serializing_if="Option::is_none")]
        required: Option<bool>,
        #[serde(skip_serializing_if="Option::is_none")]
        schema: Option<Schema>,
        #[serde(skip_serializing_if="Option::is_none")]
        #[serde(rename="uniqueItems")]
        unique_items: Option<bool>,
        #[serde(skip_serializing_if="Option::is_none")]
        #[serde(rename="type")]
        param_type: Option<String>,
        #[serde(skip_serializing_if="Option::is_none")]
        format: Option<String>,
        #[serde(skip_serializing_if="Option::is_none")]
        description: Option<String>,
    },
    Ref {
        #[serde(rename="$ref")]
        ref_path: String,
    },
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(tag = "type")]
pub enum Security {
    #[serde(rename="apiKey")]
    ApiKey {
        name: String,
        #[serde(rename="in")]
        location: String,
    },
    #[serde(rename="oauth2")]
    Oauth2 {
        flow: String,
        #[serde(rename="authorizationUrl")]
        authorization_url: String,
        #[serde(rename="tokenUrl")]
        #[serde(skip_serializing_if="Option::is_none")]
        token_url: Option<String>,
        scopes: BTreeMap<String, String>,
    },
    #[serde(rename="basic")]
    Basic,
}

/// A [JSON schema](http://json-schema.org/) definition describing
/// the shape and properties of an object.
///
/// This may also contain a `$ref` to another definition
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
pub struct Schema {
    #[serde(skip_serializing_if="Option::is_none")]
    /// a [JSON reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03)
    /// path to another defintion
    #[serde(rename="$ref")]
    pub ref_path: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="type")]
    pub schema_type: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub format: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    #[serde(rename="enum")]
    pub enum_values: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub required: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub items: Option<Box<Schema>>,
    // implies object
    #[serde(skip_serializing_if="Option::is_none")]
    pub properties: Option<BTreeMap<String, Schema>>,
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json;
    use serde_yaml;
    use std::collections::BTreeMap;

    #[test]
    fn security_api_deserializes() {
        let json = r#"{"type":"apiKey", "name":"foo", "in": "query"}"#;
        assert_eq!(
            serde_yaml::from_str::<Security>(&json).unwrap(),
            Security::ApiKey {
                name: "foo".into(),
                location: "query".into(),
            }
        );
    }

    #[test]
    fn security_api_serializes() {
        let json = r#"{"type":"apiKey","name":"foo","in":"query"}"#;
        assert_eq!(
            serde_json::to_string(
                &Security::ApiKey {
                     name: "foo".into(),
                     location: "query".into(),
                 },
            )
                    .unwrap(),
            json
        );
    }

    #[test]
    fn security_basic_deserializes() {
        let json = r#"{"type":"basic"}"#;
        assert_eq!(
            serde_yaml::from_str::<Security>(&json).unwrap(),
            Security::Basic
        );
    }

    #[test]
    fn security_basic_serializes() {
        let json = r#"{"type":"basic"}"#;
        assert_eq!(json, serde_json::to_string(&Security::Basic).unwrap());
    }

    #[test]
    fn security_oauth_deserializes() {
        let json = r#"{"type":"oauth2","flow":"implicit","authorizationUrl":"foo/bar","scopes":{"foo":"bar"}}"#;
        let mut scopes = BTreeMap::new();
        scopes.insert("foo".into(), "bar".into());
        assert_eq!(
            serde_yaml::from_str::<Security>(&json).unwrap(),
            Security::Oauth2 {
                flow: "implicit".into(),
                authorization_url: "foo/bar".into(),
                token_url: None,
                scopes: scopes,
            }
        );
    }

    #[test]
    fn security_oauth_serializes() {
        let json = r#"{"type":"oauth2","flow":"implicit","authorizationUrl":"foo/bar","scopes":{"foo":"bar"}}"#;
        let mut scopes = BTreeMap::new();
        scopes.insert("foo".into(), "bar".into());
        assert_eq!(
            json,
            serde_json::to_string(
                &Security::Oauth2 {
                     flow: "implicit".into(),
                     authorization_url: "foo/bar".into(),
                     token_url: None,
                     scopes: scopes,
                 },
            )
                    .unwrap()
        );
    }

    #[test]
    fn parameter_or_ref_deserializes_ref() {
        let json = r#"{"$ref":"foo/bar"}"#;
        assert_eq!(
            serde_yaml::from_str::<ParameterOrRef>(&json).unwrap(),
            ParameterOrRef::Ref { ref_path: "foo/bar".into() }
        );
    }

    #[test]
    fn parameter_or_ref_serializes_pref() {
        let json = r#"{"$ref":"foo/bar"}"#;
        assert_eq!(
            json,
            serde_json::to_string(&ParameterOrRef::Ref { ref_path: "foo/bar".into() }).unwrap()
        );
    }
}
<|endoftext|>