<commit_before>//! Utilities for defining a JSON parser.

use util::Id;

use std::cell::RefCell;
use std::collections::{ HashMap, HashSet };
use std::error::Error as StdError;
use std::fmt::{ Display, Debug, Error as FmtError, Formatter };
use std::hash::Hash;
use std::rc::Rc;
use std::sync::Arc;

use serde_json::error;
use serde::ser::{ Serialize, Serializer };
use serde_json;
pub use serde_json::value::Value as JSON;
use serde::de::Error;

/// Utility function: Make sure that we have consumed all the fields of an object.
pub fn check_fields(path: Path, json: &JSON) -> Result<(), ParseError> {
    if let JSON::Object(ref obj) = *json {
        if obj.is_empty() {
            Ok(())
        } else {
            Err(ParseError::unknown_fields(obj.keys().cloned().collect(), &path))
        }
    } else {
        Ok(())
    }
}

/// A path in the JSON tree. Used for displaying error messages.
#[derive(Clone, Debug)]
pub struct Path {
    buf: Rc<RefCell<String>>,
    len: usize,
}
impl Path {
    /// Create an empty Path.
    pub fn new() -> Self {
        Path {
            buf: Rc::new(RefCell::new(String::new())),
            len: 0,
        }
    }

    /// Push a suffix after a path.
    pub fn push_str<F, T>(&self, suffix: &str, cb: F) -> T
        where F: FnOnce(Path) -> T
    {
        let buf = self.buf.clone();
        let len;
        {
            let mut str = buf.borrow_mut();
            str.push_str(suffix);
            len = str.len();
        }
        let path = Path {
            buf: buf,
            len: len,
        };
        let result = cb(path);
        {
            let mut str = self.buf.borrow_mut();
            str.truncate(self.len)
        }
        result
    }

    pub fn push_index<F, T>(&self, index: usize, cb: F) -> T
        where F: FnOnce(Path) -> T
    {
        self.push_str(&format!("[{}]", index), cb)
    }

    pub fn push<F, T>(&self, suffix: &str, cb: F) -> T
        where F: FnOnce(Path) -> T
    {
        self.push_str(&format!(".{}", suffix), cb)
    }

    pub fn to_string(&self) -> String {
        let mut str = self.buf.borrow().clone();
        str.truncate(self.len);
        str
    }
}

/// An error during parsing.
#[derive(Debug)]
pub enum ParseError {
    JSON(JSONError),
    MissingField {
        name: String,
        at: String,
    },
    UnknownFields {
        names: Vec<String>,
        at: String,
    },
    TypeError {
        name: String,
        at: String,
        expected: String,
    },
    EmptyObject {
        at: String
    },
    UnknownConstant {
        at: String,
        constant: String,
    }
}

impl Display for ParseError {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        (self as &Debug).fmt(formatter)
    }
}
impl StdError for ParseError {
    fn description(&self) -> &str {
        "Error while parsing to JSON"
    }
}

impl ParseError {
    pub fn missing_field(name: &str, at: &Path) -> Self {
        ParseError::MissingField {
            name: name.to_owned(),
            at: at.to_string(),
        }
    }
    pub fn type_error(name: &str, at: &Path, expected: &str) -> Self {
        ParseError::TypeError {
            name: name.to_owned(),
            at: at.to_string(),
            expected: expected.to_owned()
        }
    }
    pub fn unknown_fields(names: Vec<String>, at: &Path) -> Self {
        ParseError::UnknownFields {
            names: names,
            at: at.to_string()
        }
    }
    pub fn unknown_constant(value: &str, at: &Path) -> Self {
        ParseError::UnknownConstant {
            constant: value.to_owned(),
            at: at.to_string()
        }
    }
    pub fn empty_object(at: &Path) -> Self {
        ParseError::EmptyObject {
            at: at.to_string(),
        }
    }
    pub fn json(error: error::Error) -> Self {
        ParseError::JSON(JSONError(error))
    }
}

#[derive(Debug)]
pub struct JSONError(error::Error);

impl Serialize for JSONError {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer
    {
        serializer.serialize_str(&format!("{:?}", self))
    }
}

/// An object that knows how to parse values from JSON into type T.
///
/// The JSON object is expected to be consumed along the way. A successful parse will
/// typically leave an empty JSON object.
pub trait Parser<T: Sized> {
    fn description() -> String;
    fn from_str(source: &str) -> Result<T, ParseError> {
        match serde_json::from_str(source) {
            Err(err) => Err(ParseError::json(err)),
            Ok(mut json) => Self::parse(Path::new(), &mut json)
        }
    }

    /// Parse a single value from JSON, consuming as much as necessary from JSON.
    fn parse(path: Path, source: &mut JSON) -> Result<T, ParseError>;

    /// Parse a field from JSON, consuming it.
    fn take(path: Path, source: &mut JSON, field_name: &str) -> Result<T, ParseError> {
        match Self::take_opt(path.clone(), source, field_name) {
            Some(result) => result,
            None => Err(ParseError::missing_field(field_name, &path))
        }
    }

    /// Parse a field from JSON, consuming it.
    fn take_opt(path: Path, source: &mut JSON, field_name: &str) -> Option<Result<T, ParseError>> {
        if let JSON::Object(ref mut obj) = *source {
            if let Some(mut v) = obj.remove(field_name) {
                Some(Self::parse(path, &mut v))
            } else {
                None
            }
        } else {
            Some(Err(ParseError::type_error(field_name, &path, "object")))
        }
    }

    /// Parse a field containing an array from JSON, consuming the field.
    fn take_vec_opt(path: Path, source: &mut JSON, field_name: &str) -> Option<Result<Vec<T>, ParseError>>
    {
        if let JSON::Object(ref mut obj) = *source {
            if let Some(ref mut json) = obj.remove(field_name) {
                if let JSON::Array(ref mut vec) = *json {
                    let mut result = Vec::with_capacity(vec.len());
                    for (json, i) in vec.iter_mut().zip(0..) {
                        match path.push(&format!("[{}]", i),
                            |path| Self::parse(path, json)
                        ) {
                            Err(error) => return Some(Err(error)),
                            Ok(parsed) => result.push(parsed)
                        }
                    }
                    Some(Ok(result))
                } else {
                    Some(Err(ParseError::type_error(field_name, &path, "array")))
                }
            } else {
                None
            }
        } else {
            Some(Err(ParseError::missing_field(field_name, &path)))
        }
    }

    fn take_vec(path: Path, source: &mut JSON, field_name: &str) -> Result<Vec<T>, ParseError> {
        match Self::take_vec_opt(path.clone(), source, field_name) {
            Some(result) => result,
            None => Err(ParseError::missing_field(field_name, &path))
        }
    }
}

impl Parser<f64> for f64 {
    fn description() -> String {
        "Number".to_owned()
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        match *source {
            JSON::I64(val) => Ok(val as f64),
            JSON::F64(val) => Ok(val),
            JSON::U64(val) => Ok(val as f64),
            _ => Err(ParseError::type_error("as float", &path, "number"))
        }
    }
}

impl Parser<bool> for bool {
    fn description() -> String {
        "bool".to_owned()
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        match *source {
            JSON::Bool(ref b) => Ok(*b),
            JSON::U64(0) | JSON::I64(0) => Ok(false),
            JSON::U64(1) | JSON::I64(1) => Ok(true),
            JSON::String(ref str) if str == "true" => Ok(true),
            JSON::String(ref str) if str == "false" => Ok(false),
            _ => Err(ParseError::type_error("as bool", &path, "boolean"))
        }
    }
}

impl Parser<u8> for u8 {
    fn description() -> String {
        "byte".to_owned()
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        match source.as_u64() {
            None => Err(ParseError::type_error("as byte", &path, "positive integer")),
            Some(ref val) if *val > u8::max_value() as u64 =>
                Err(ParseError::type_error("as byte", &path, "positive integer")),
            Some(ref val) => Ok(*val as u8)
        }
    }
}

impl<T> Parser<Vec<T>> for Vec<T> where T: Parser<T> {
    fn description() -> String {
        format!("Array<{}>", T::description())
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        // Otherwise, parse as an actual array.
        match *source {
            JSON::Array(ref mut array) => {
                let mut result = Vec::with_capacity(array.len());
                for (source, i) in array.iter_mut ().zip(0..) {
                    let value = try!(path.push_index(i, |path| T::parse(path, source)));
                    result.push(value)
                }
                Ok(result)
            }
            JSON::Null => {
                // Accept `null` as an empty array.
                Ok(vec![])
            }
            _ => {
                // Attempt to promote the value to an array.
                let single = try!(path.push_str("", |path| T::parse(path, source)));
                Ok(vec![single])
            }
        }
    }
}

/*
impl<T, U> Parser<(T, U)> for (T, U) where T: Parser<T>, U: Parser<U> {
    fn description() -> String {
        format!("({}, {})", T::description(), U::description())
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        match *source {
            JSON::Array(ref mut array) if array.len() == 2 => {
                let mut right = array.pop().unwrap(); // We just checked that length == 2
                let mut left = array.pop().unwrap(); // We just checked that length == 2
                let left_parsed = try!(path.push(&T::description() as &str, |path| {T::parse(path, &mut left)}));
                let right_parsed = try!(path.push(&U::description() as &str, |path| {U::parse(path, &mut right)}));
                Ok((left_parsed, right_parsed))
            }
            _ => Err(ParseError::type_error("pair of values", &path, "array"))
        }
    }
}
*/
impl Parser<String> for String {
    fn description() -> String {
        "String".to_owned()
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        match source.as_string() {
            Some(str) => Ok(str.to_owned()),
            None => Err(ParseError::type_error("string", &path, "string"))
        }
    }
}

impl<T> Parser<Arc<T>> for Arc<T> where T: Parser<T> {
    fn description() -> String {
        T::description()
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        Ok(Arc::new(try!(T::parse(path, source))))
    }
}

pub trait ToJSON {
    fn to_json(&self) -> JSON;
}

impl ToJSON for String {
    fn to_json(&self) -> JSON {
        JSON::String(self.clone())
    }
}

impl ToJSON for bool {
    fn to_json(&self) -> JSON {
        JSON::Bool(*self)
    }
}

impl ToJSON for f64 {
    fn to_json(&self) -> JSON {
        JSON::F64(*self)
    }
}

impl ToJSON for usize {
    fn to_json(&self) -> JSON {
        JSON::U64(*self as u64)
    }
}

impl ToJSON for JSON {
    fn to_json(&self) -> JSON {
        self.clone()
    }
}

impl<T> ToJSON for HashSet<T> where T: ToJSON + Eq + Hash {
    fn to_json(&self) -> JSON {
        JSON::Array((*self).iter().map(T::to_json).collect())
    }
}

impl<T> ToJSON for HashMap<String, T> where T: ToJSON {
    fn to_json(&self) -> JSON {
        JSON::Object(self.iter().map(|(k, v)| (k.clone(), T::to_json(v))).collect())
    }
}

impl<T> ToJSON for Vec<T> where T: ToJSON {
    fn to_json(&self) -> JSON {
        JSON::Array(self.iter().map(|x| x.to_json()).collect())
    }
}

impl<'a, T> ToJSON for Vec<(&'a str, T)> where T: ToJSON {
    fn to_json(&self) -> JSON {
        JSON::Object(self.iter().map(|&(ref k, ref v)| {
            ((*k).to_owned(), v.to_json())
        }).collect())
    }
}

impl <'a> ToJSON for &'a str {
    fn to_json(&self) -> JSON {
        JSON::String((*self).to_owned())
    }
}

impl<'a, T> ToJSON for &'a T where T: ToJSON {
    fn to_json(&self) -> JSON {
        (**self).to_json()
    }
}

impl<K, T, V> ToJSON for HashMap<Id<K>, Result<T, V>> where T: ToJSON, V: ToJSON {
    fn to_json(&self) -> JSON {
        JSON::Object(self.iter().map(|(k, result)| {
            let k = k.to_string();
            let result = match *result {
                Ok(ref ok) => ok.to_json(),
                Err(ref err) => vec![("Error", err)].to_json()
            };
            (k, result)
        }).collect())
    }
}

impl<T> ToJSON for Option<T> where T: ToJSON {
    fn to_json(&self) -> JSON {
        match *self {
            None => JSON::Null,
            Some(ref result) => result.to_json()
        }
    }
}

impl ToJSON for () {
    fn to_json(&self) -> JSON {
        JSON::Null
    }
}

/*
impl<T> Parser<T> for T where T: Deserialize {
    fn parse(_: Path, source: &mut JSON) -> Result<T, ParseError> {
        use serde_json;
        serde_json::from_value(source.clone()).map_err(ParseError::json)
    }
}
*/
<commit_msg>Implementing Parse::from_str_at<commit_after>//! Utilities for defining a JSON parser.

use util::Id;

use std::cell::RefCell;
use std::collections::{ HashMap, HashSet };
use std::error::Error as StdError;
use std::fmt::{ Display, Debug, Error as FmtError, Formatter };
use std::hash::Hash;
use std::rc::Rc;
use std::sync::Arc;

use serde_json::error;
use serde::ser::{ Serialize, Serializer };
use serde_json;
pub use serde_json::value::Value as JSON;
use serde::de::Error;

/// Utility function: Make sure that we have consumed all the fields of an object.
pub fn check_fields(path: Path, json: &JSON) -> Result<(), ParseError> {
    if let JSON::Object(ref obj) = *json {
        if obj.is_empty() {
            Ok(())
        } else {
            Err(ParseError::unknown_fields(obj.keys().cloned().collect(), &path))
        }
    } else {
        Ok(())
    }
}

/// A path in the JSON tree. Used for displaying error messages.
#[derive(Clone, Debug)]
pub struct Path {
    buf: Rc<RefCell<String>>,
    len: usize,
}
impl Path {
    /// Create an empty Path.
    pub fn new() -> Self {
        Path {
            buf: Rc::new(RefCell::new(String::new())),
            len: 0,
        }
    }

    /// Push a suffix after a path.
    pub fn push_str<F, T>(&self, suffix: &str, cb: F) -> T
        where F: FnOnce(Path) -> T
    {
        let buf = self.buf.clone();
        let len;
        {
            let mut str = buf.borrow_mut();
            str.push_str(suffix);
            len = str.len();
        }
        let path = Path {
            buf: buf,
            len: len,
        };
        let result = cb(path);
        {
            let mut str = self.buf.borrow_mut();
            str.truncate(self.len)
        }
        result
    }

    pub fn push_index<F, T>(&self, index: usize, cb: F) -> T
        where F: FnOnce(Path) -> T
    {
        self.push_str(&format!("[{}]", index), cb)
    }

    pub fn push<F, T>(&self, suffix: &str, cb: F) -> T
        where F: FnOnce(Path) -> T
    {
        self.push_str(&format!(".{}", suffix), cb)
    }

    pub fn to_string(&self) -> String {
        let mut str = self.buf.borrow().clone();
        str.truncate(self.len);
        str
    }
}

/// An error during parsing.
#[derive(Debug)]
pub enum ParseError {
    JSON(JSONError),
    MissingField {
        name: String,
        at: String,
    },
    UnknownFields {
        names: Vec<String>,
        at: String,
    },
    TypeError {
        name: String,
        at: String,
        expected: String,
    },
    EmptyObject {
        at: String
    },
    UnknownConstant {
        at: String,
        constant: String,
    }
}

impl Display for ParseError {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        (self as &Debug).fmt(formatter)
    }
}
impl StdError for ParseError {
    fn description(&self) -> &str {
        "Error while parsing to JSON"
    }
}

impl ParseError {
    pub fn missing_field(name: &str, at: &Path) -> Self {
        ParseError::MissingField {
            name: name.to_owned(),
            at: at.to_string(),
        }
    }
    pub fn type_error(name: &str, at: &Path, expected: &str) -> Self {
        ParseError::TypeError {
            name: name.to_owned(),
            at: at.to_string(),
            expected: expected.to_owned()
        }
    }
    pub fn unknown_fields(names: Vec<String>, at: &Path) -> Self {
        ParseError::UnknownFields {
            names: names,
            at: at.to_string()
        }
    }
    pub fn unknown_constant(value: &str, at: &Path) -> Self {
        ParseError::UnknownConstant {
            constant: value.to_owned(),
            at: at.to_string()
        }
    }
    pub fn empty_object(at: &Path) -> Self {
        ParseError::EmptyObject {
            at: at.to_string(),
        }
    }
    pub fn json(error: error::Error) -> Self {
        ParseError::JSON(JSONError(error))
    }
}

#[derive(Debug)]
pub struct JSONError(error::Error);

impl Serialize for JSONError {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer
    {
        serializer.serialize_str(&format!("{:?}", self))
    }
}

/// An object that knows how to parse values from JSON into type T.
///
/// The JSON object is expected to be consumed along the way. A successful parse will
/// typically leave an empty JSON object.
pub trait Parser<T: Sized> {
    fn description() -> String;
    fn from_str(source: &str) -> Result<T, ParseError> {
        Self::from_str_at(Path::new(), source)
    }
    fn from_str_at(path: Path, source: &str) -> Result<T, ParseError> {
        match serde_json::from_str(source) {
            Err(err) => Err(ParseError::json(err)),
            Ok(mut json) => Self::parse(path, &mut json)
        }
    }

    /// Parse a single value from JSON, consuming as much as necessary from JSON.
    fn parse(path: Path, source: &mut JSON) -> Result<T, ParseError>;

    /// Parse a field from JSON, consuming it.
    fn take(path: Path, source: &mut JSON, field_name: &str) -> Result<T, ParseError> {
        match Self::take_opt(path.clone(), source, field_name) {
            Some(result) => result,
            None => Err(ParseError::missing_field(field_name, &path))
        }
    }

    /// Parse a field from JSON, consuming it.
    fn take_opt(path: Path, source: &mut JSON, field_name: &str) -> Option<Result<T, ParseError>> {
        if let JSON::Object(ref mut obj) = *source {
            if let Some(mut v) = obj.remove(field_name) {
                Some(Self::parse(path, &mut v))
            } else {
                None
            }
        } else {
            Some(Err(ParseError::type_error(field_name, &path, "object")))
        }
    }

    /// Parse a field containing an array from JSON, consuming the field.
    fn take_vec_opt(path: Path, source: &mut JSON, field_name: &str) -> Option<Result<Vec<T>, ParseError>>
    {
        if let JSON::Object(ref mut obj) = *source {
            if let Some(ref mut json) = obj.remove(field_name) {
                if let JSON::Array(ref mut vec) = *json {
                    let mut result = Vec::with_capacity(vec.len());
                    for (json, i) in vec.iter_mut().zip(0..) {
                        match path.push(&format!("[{}]", i),
                            |path| Self::parse(path, json)
                        ) {
                            Err(error) => return Some(Err(error)),
                            Ok(parsed) => result.push(parsed)
                        }
                    }
                    Some(Ok(result))
                } else {
                    Some(Err(ParseError::type_error(field_name, &path, "array")))
                }
            } else {
                None
            }
        } else {
            Some(Err(ParseError::missing_field(field_name, &path)))
        }
    }

    fn take_vec(path: Path, source: &mut JSON, field_name: &str) -> Result<Vec<T>, ParseError> {
        match Self::take_vec_opt(path.clone(), source, field_name) {
            Some(result) => result,
            None => Err(ParseError::missing_field(field_name, &path))
        }
    }
}

impl Parser<f64> for f64 {
    fn description() -> String {
        "Number".to_owned()
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        match *source {
            JSON::I64(val) => Ok(val as f64),
            JSON::F64(val) => Ok(val),
            JSON::U64(val) => Ok(val as f64),
            _ => Err(ParseError::type_error("as float", &path, "number"))
        }
    }
}

impl Parser<bool> for bool {
    fn description() -> String {
        "bool".to_owned()
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        match *source {
            JSON::Bool(ref b) => Ok(*b),
            JSON::U64(0) | JSON::I64(0) => Ok(false),
            JSON::U64(1) | JSON::I64(1) => Ok(true),
            JSON::String(ref str) if str == "true" => Ok(true),
            JSON::String(ref str) if str == "false" => Ok(false),
            _ => Err(ParseError::type_error("as bool", &path, "boolean"))
        }
    }
}

impl Parser<u8> for u8 {
    fn description() -> String {
        "byte".to_owned()
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        match source.as_u64() {
            None => Err(ParseError::type_error("as byte", &path, "positive integer")),
            Some(ref val) if *val > u8::max_value() as u64 =>
                Err(ParseError::type_error("as byte", &path, "positive integer")),
            Some(ref val) => Ok(*val as u8)
        }
    }
}

impl<T> Parser<Vec<T>> for Vec<T> where T: Parser<T> {
    fn description() -> String {
        format!("Array<{}>", T::description())
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        // Otherwise, parse as an actual array.
        match *source {
            JSON::Array(ref mut array) => {
                let mut result = Vec::with_capacity(array.len());
                for (source, i) in array.iter_mut ().zip(0..) {
                    let value = try!(path.push_index(i, |path| T::parse(path, source)));
                    result.push(value)
                }
                Ok(result)
            }
            JSON::Null => {
                // Accept `null` as an empty array.
                Ok(vec![])
            }
            _ => {
                // Attempt to promote the value to an array.
                let single = try!(path.push_str("", |path| T::parse(path, source)));
                Ok(vec![single])
            }
        }
    }
}

/*
impl<T, U> Parser<(T, U)> for (T, U) where T: Parser<T>, U: Parser<U> {
    fn description() -> String {
        format!("({}, {})", T::description(), U::description())
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        match *source {
            JSON::Array(ref mut array) if array.len() == 2 => {
                let mut right = array.pop().unwrap(); // We just checked that length == 2
                let mut left = array.pop().unwrap(); // We just checked that length == 2
                let left_parsed = try!(path.push(&T::description() as &str, |path| {T::parse(path, &mut left)}));
                let right_parsed = try!(path.push(&U::description() as &str, |path| {U::parse(path, &mut right)}));
                Ok((left_parsed, right_parsed))
            }
            _ => Err(ParseError::type_error("pair of values", &path, "array"))
        }
    }
}
*/
impl Parser<String> for String {
    fn description() -> String {
        "String".to_owned()
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        match source.as_string() {
            Some(str) => Ok(str.to_owned()),
            None => Err(ParseError::type_error("string", &path, "string"))
        }
    }
}

impl<T> Parser<Arc<T>> for Arc<T> where T: Parser<T> {
    fn description() -> String {
        T::description()
    }
    fn parse(path: Path, source: &mut JSON) -> Result<Self, ParseError> {
        Ok(Arc::new(try!(T::parse(path, source))))
    }
}

pub trait ToJSON {
    fn to_json(&self) -> JSON;
}

impl ToJSON for String {
    fn to_json(&self) -> JSON {
        JSON::String(self.clone())
    }
}

impl ToJSON for bool {
    fn to_json(&self) -> JSON {
        JSON::Bool(*self)
    }
}

impl ToJSON for f64 {
    fn to_json(&self) -> JSON {
        JSON::F64(*self)
    }
}

impl ToJSON for usize {
    fn to_json(&self) -> JSON {
        JSON::U64(*self as u64)
    }
}

impl ToJSON for JSON {
    fn to_json(&self) -> JSON {
        self.clone()
    }
}

impl<T> ToJSON for HashSet<T> where T: ToJSON + Eq + Hash {
    fn to_json(&self) -> JSON {
        JSON::Array((*self).iter().map(T::to_json).collect())
    }
}

impl<T> ToJSON for HashMap<String, T> where T: ToJSON {
    fn to_json(&self) -> JSON {
        JSON::Object(self.iter().map(|(k, v)| (k.clone(), T::to_json(v))).collect())
    }
}

impl<T> ToJSON for Vec<T> where T: ToJSON {
    fn to_json(&self) -> JSON {
        JSON::Array(self.iter().map(|x| x.to_json()).collect())
    }
}

impl<'a, T> ToJSON for Vec<(&'a str, T)> where T: ToJSON {
    fn to_json(&self) -> JSON {
        JSON::Object(self.iter().map(|&(ref k, ref v)| {
            ((*k).to_owned(), v.to_json())
        }).collect())
    }
}

impl <'a> ToJSON for &'a str {
    fn to_json(&self) -> JSON {
        JSON::String((*self).to_owned())
    }
}

impl<'a, T> ToJSON for &'a T where T: ToJSON {
    fn to_json(&self) -> JSON {
        (**self).to_json()
    }
}

impl<K, T, V> ToJSON for HashMap<Id<K>, Result<T, V>> where T: ToJSON, V: ToJSON {
    fn to_json(&self) -> JSON {
        JSON::Object(self.iter().map(|(k, result)| {
            let k = k.to_string();
            let result = match *result {
                Ok(ref ok) => ok.to_json(),
                Err(ref err) => vec![("Error", err)].to_json()
            };
            (k, result)
        }).collect())
    }
}

impl<T> ToJSON for Option<T> where T: ToJSON {
    fn to_json(&self) -> JSON {
        match *self {
            None => JSON::Null,
            Some(ref result) => result.to_json()
        }
    }
}

impl ToJSON for () {
    fn to_json(&self) -> JSON {
        JSON::Null
    }
}

/*
impl<T> Parser<T> for T where T: Deserialize {
    fn parse(_: Path, source: &mut JSON) -> Result<T, ParseError> {
        use serde_json;
        serde_json::from_value(source.clone()).map_err(ParseError::json)
    }
}
*/
<|endoftext|>


<commit_before>use filter;
use filter_tree;
use ColorConfig;
use formatter;
use walkdir;
use walkdir::WalkDir;
use walkdir::DirEntry;
use walkdir::WalkDirIterator;
use parser;
use nom::IResult;
use nom::Needed;
use mime_guess;
use liquid;
use liquid::{Renderable, Context, Value};
use termion::{is_tty};
use std::fs;
use std::os::unix::fs::MetadataExt;
use std::process;
use std::process::Command;

fn stdout_is_tty() -> bool {
    is_tty(&fs::File::create("/dev/stdout").unwrap())
}

pub struct Query {
    attributes: Vec<filter::Attribute>,
    directories: Vec<String>,
    filters: filter_tree::FilterTree,
    command: Option<String>,
    machine_mode: bool,
}

fn is_hidden(entry: &DirEntry) -> bool {
    entry.path()
         .to_str()
         .map(|s| s.contains("/."))
         .unwrap_or(false)
}

impl Query {
    pub fn new(attributes: Option<Vec<filter::Attribute>>, directories: Option<Vec<String>>, filters: Option<filter_tree::FilterTree>, command: Option<String>) -> Query{
        let mut attr = attributes.unwrap_or(vec![filter::Attribute::Name]);
        let dirs = directories.unwrap_or(vec![String::from(".")]);
        let filters = filters.unwrap_or(filter_tree::FilterTree::new(None, None, None));
        if attr.len() == 0 {
            attr.push(filter::Attribute::Name);
        }
        Query{attributes: attr, directories: dirs, filters: filters, command: command, machine_mode: false}
    }

    pub fn parse(inp: &str) -> Query {
        match parser::query(inp.as_bytes()){
            IResult::Done(leftovers, q)     => {
                if leftovers.len() > 1 {
                    eprintln!("Could not parse from here -> {}\nDid you make a typo?\n\n", String::from_utf8_lossy(leftovers).into_owned());
                    process::exit(1);
                };
                q
            },
            IResult::Error(e)               => {
                eprintln!("Syntax error {}", e);
                process::exit(1);
            },
            IResult::Incomplete(n)          => match n {
                    Needed::Unknown         => {
                        eprintln!("Need more input, but I haven't got a clou how much!");
                        process::exit(1);
                    },
                    Needed::Size(n)         => {
                        eprintln!("Need {}bytes more input!", n);
                        process::exit(1);
                    },
                },
        }
    }

    fn print_attributes(&self, entry: &DirEntry, color_config: &Option<ColorConfig>, color_mode: bool) {
        let mut print_string = String::from("");
        for attribute in &self.attributes {
            let attr_str = match *attribute {
                filter::Attribute::Name	    => formatter::format_name(entry, color_config, color_mode),
                filter::Attribute::Basename	=> format!("{}", entry.file_name().to_str().unwrap()),
                filter::Attribute::Size	    => formatter::format_filesize(entry.metadata().unwrap().len(), self.machine_mode),
                filter::Attribute::Mtime	=> formatter::format_systime(entry.metadata().unwrap().modified().unwrap(), self.machine_mode),
                filter::Attribute::Ctime	=> {
                    match entry.metadata().unwrap().created() {
                        Ok(t)   => formatter::format_systime(t, self.machine_mode),
                        Err(_)  => String::from("N/A"),
                    }},
                filter::Attribute::Atime    => {
                    match entry.metadata().unwrap().accessed() {
                        Ok(t)   => formatter::format_systime(t, self.machine_mode),
                        Err(_)  => String::from("N/A"),
                    }},
                filter::Attribute::Filetype	=> formatter::format_filetype(entry.metadata().unwrap().file_type(), self.machine_mode),
                filter::Attribute::Mimetype	=> {
                    let filepath = format!("{}", entry.path().display());
                    formatter::format_mimetype(mime_guess::guess_mime_type(filepath), self.machine_mode)
                },
                filter::Attribute::Inode	=> format!("{}", entry.ino()),
                filter::Attribute::Uid 	    => format!("{}", entry.metadata().unwrap().uid()),
                filter::Attribute::Gid 	    => format!("{}", entry.metadata().unwrap().gid()),
            };
            if !print_string.is_empty() {
                print_string.push(',');
            }
            print_string.push_str(attr_str.as_str());
        }
        println!("{}", print_string);
    }

    fn setup_context(&self, dir_entry: &DirEntry) -> Context {
        // TODO does this need speed improvement? All attributes will be needed rarely...
        let mut context = Context::new();
        context.set_val("name", Value::Str(String::from(dir_entry.path().to_str().unwrap())));
        context.set_val("basename", Value::Str(String::from(dir_entry.file_name().to_str().unwrap())));
        context.set_val("size", Value::Str(formatter::format_filesize(dir_entry.metadata().unwrap().len(), self.machine_mode)));
        context.set_val("mtime", Value::Str(formatter::format_systime(dir_entry.metadata().unwrap().modified().unwrap(), self.machine_mode)));
        let ctime = match dir_entry.metadata().unwrap().created() {
                Ok(t)   => formatter::format_systime(t, self.machine_mode),
                Err(_)  => String::from("N/A"),
        };
        context.set_val("ctime", Value::Str(ctime));

        let atime = match dir_entry.metadata().unwrap().accessed() {
                Ok(t)   => formatter::format_systime(t, self.machine_mode),
                Err(_)  => String::from("N/A"),
            };
        context.set_val("atime", Value::Str(atime));

        context.set_val("type", Value::Str(formatter::format_filetype(dir_entry.metadata().unwrap().file_type(), self.machine_mode)));
        context.set_val("mimetype", Value::Str(formatter::format_mimetype(mime_guess::guess_mime_type(dir_entry.path().to_str().unwrap()), self.machine_mode)));
        context.set_val("inode", Value::Str(format!("{}", dir_entry.ino())));
        return context;
    }

    fn run_command(&self, dir_entry: &DirEntry) {
        match self.command {
            None    => {},
            Some(ref c) => {
                let template = liquid::parse(c, Default::default()).unwrap();
                let mut context = self.setup_context(dir_entry);
                let output = template.render(&mut context);
                match output {
                    Ok(res) => Command::new("sh").arg("-c").arg(res.unwrap()).spawn().expect("Failed to start command."),
                    Err(e)    => {
                        eprintln!("Command template error: {}", e);
                        process::exit(1);
                    },
                };
            },
        }
    }

    fn raw_walk(&self, dir: &String, max_depth: usize, color_config: &Option<ColorConfig>, color_mode: bool) {
        let dir_iter = WalkDir::new(dir).max_depth(max_depth).into_iter();

        'files: for entry in dir_iter {
            let entry = match entry{
                Ok(e)  => e,
                Err(e) => {
                    eprintln!("Error: {}", e);
                    continue 'files;
                }
            };
            if self.filters.test(&entry) != true {
                    continue 'files;
            }
            self.print_attributes(&entry, color_config, color_mode);
            self.run_command(&entry);
        }
    }

    fn process_entry(&self, entry: Result<DirEntry, walkdir::Error>, color_config: &Option<ColorConfig>, color_mode: bool){
        let entry = match entry{
            Ok(e)  => e,
            Err(e) => {
                eprintln!("Error: {}", e);
                return;
            }
        };
        if self.filters.test(&entry) == true {
            self.print_attributes(&entry, color_config, color_mode);
            self.run_command(&entry);
        }
    }

    fn dev_walk(&self, dir: &String, max_depth: usize, color_config: &Option<ColorConfig>, color_mode: bool, same_device: bool, ignore_hidden: bool){
        let dir_iter = WalkDir::new(dir).max_depth(max_depth).into_iter();

        let dev_id = match WalkDir::new(dir).into_iter().next() {
            Some(e) => {
                let dir_entry = e.expect("Failed to open directory entry.",);
                dir_entry.metadata().map(|m| m.dev()).expect(&format!("Could not get device id from {:?}.", dir_entry))
            }
            None => {
                eprintln!("{} not found!", dir);
                process::exit(1);
            },
        };

        if same_device && ignore_hidden {
            let filtered_iter = dir_iter.filter_entry(|e| e.metadata().map(|m| m.dev() == dev_id).unwrap_or(false))
                                        .filter_entry(|e| !is_hidden(e));
            for entry in filtered_iter {
                self.process_entry(entry, color_config, color_mode);
            }
        } else if same_device {
            let filtered_iter = dir_iter.filter_entry(|e| e.metadata().map(|m| m.dev() == dev_id).unwrap_or(false));
            for entry in filtered_iter {
                self.process_entry(entry, color_config, color_mode);
            }
        } else if ignore_hidden {
            let filtered_iter = dir_iter.filter_entry(|e| !is_hidden(e));
            for entry in filtered_iter {
                self.process_entry(entry, color_config, color_mode);
            }
        } else {
            eprintln!("Implementation error: Use raw_walk instead!");
            process::exit(1);
        }
    }

    pub fn execute(&mut self, max_depth: usize, machine_mode: bool, ignore_hidden: bool, same_device: bool, color: bool, color_config: Option<ColorConfig>) {
        let color_mode = if color {
            stdout_is_tty()
        } else {
            false
        };

        if machine_mode {
            self.machine_mode = true
        }

        for dir in &self.directories {
            if same_device || ignore_hidden {
                self.dev_walk(dir, max_depth, &color_config, color_mode, same_device, ignore_hidden);
            } else {
                self.raw_walk(dir, max_depth, &color_config, color_mode);
            }
        }
    }
}
<commit_msg>Return 'N/A' on UTF-8 Errors in exec part<commit_after>use filter;
use filter_tree;
use ColorConfig;
use formatter;
use walkdir;
use walkdir::WalkDir;
use walkdir::DirEntry;
use walkdir::WalkDirIterator;
use parser;
use nom::IResult;
use nom::Needed;
use mime_guess;
use liquid;
use liquid::{Renderable, Context, Value};
use termion::{is_tty};
use std::fs;
use std::os::unix::fs::MetadataExt;
use std::process;
use std::process::Command;

fn stdout_is_tty() -> bool {
    is_tty(&fs::File::create("/dev/stdout").unwrap())
}

pub struct Query {
    attributes: Vec<filter::Attribute>,
    directories: Vec<String>,
    filters: filter_tree::FilterTree,
    command: Option<String>,
    machine_mode: bool,
}

fn is_hidden(entry: &DirEntry) -> bool {
    entry.path()
         .to_str()
         .map(|s| s.contains("/."))
         .unwrap_or(false)
}

impl Query {
    pub fn new(attributes: Option<Vec<filter::Attribute>>, directories: Option<Vec<String>>, filters: Option<filter_tree::FilterTree>, command: Option<String>) -> Query{
        let mut attr = attributes.unwrap_or(vec![filter::Attribute::Name]);
        let dirs = directories.unwrap_or(vec![String::from(".")]);
        let filters = filters.unwrap_or(filter_tree::FilterTree::new(None, None, None));
        if attr.len() == 0 {
            attr.push(filter::Attribute::Name);
        }
        Query{attributes: attr, directories: dirs, filters: filters, command: command, machine_mode: false}
    }

    pub fn parse(inp: &str) -> Query {
        match parser::query(inp.as_bytes()){
            IResult::Done(leftovers, q)     => {
                if leftovers.len() > 1 {
                    eprintln!("Could not parse from here -> {}\nDid you make a typo?\n\n", String::from_utf8_lossy(leftovers).into_owned());
                    process::exit(1);
                };
                q
            },
            IResult::Error(e)               => {
                eprintln!("Syntax error {}", e);
                process::exit(1);
            },
            IResult::Incomplete(n)          => match n {
                    Needed::Unknown         => {
                        eprintln!("Need more input, but I haven't got a clou how much!");
                        process::exit(1);
                    },
                    Needed::Size(n)         => {
                        eprintln!("Need {}bytes more input!", n);
                        process::exit(1);
                    },
                },
        }
    }

    fn print_attributes(&self, entry: &DirEntry, color_config: &Option<ColorConfig>, color_mode: bool) {
        let mut print_string = String::from("");
        for attribute in &self.attributes {
            let attr_str = match *attribute {
                filter::Attribute::Name	    => formatter::format_name(entry, color_config, color_mode),
                filter::Attribute::Basename	=> format!("{}", entry.file_name().to_str().unwrap()),
                filter::Attribute::Size	    => formatter::format_filesize(entry.metadata().unwrap().len(), self.machine_mode),
                filter::Attribute::Mtime	=> formatter::format_systime(entry.metadata().unwrap().modified().unwrap(), self.machine_mode),
                filter::Attribute::Ctime	=> {
                    match entry.metadata().unwrap().created() {
                        Ok(t)   => formatter::format_systime(t, self.machine_mode),
                        Err(_)  => String::from("N/A"),
                    }},
                filter::Attribute::Atime    => {
                    match entry.metadata().unwrap().accessed() {
                        Ok(t)   => formatter::format_systime(t, self.machine_mode),
                        Err(_)  => String::from("N/A"),
                    }},
                filter::Attribute::Filetype	=> formatter::format_filetype(entry.metadata().unwrap().file_type(), self.machine_mode),
                filter::Attribute::Mimetype	=> {
                    let filepath = format!("{}", entry.path().display());
                    formatter::format_mimetype(mime_guess::guess_mime_type(filepath), self.machine_mode)
                },
                filter::Attribute::Inode	=> format!("{}", entry.ino()),
                filter::Attribute::Uid 	    => format!("{}", entry.metadata().unwrap().uid()),
                filter::Attribute::Gid 	    => format!("{}", entry.metadata().unwrap().gid()),
            };
            if !print_string.is_empty() {
                print_string.push(',');
            }
            print_string.push_str(attr_str.as_str());
        }
        println!("{}", print_string);
    }

    fn setup_context(&self, dir_entry: &DirEntry) -> Context {
        // TODO does this need speed improvement? All attributes will be needed rarely...
        let mut context = Context::new();
        context.set_val("name", Value::Str(String::from( dir_entry.path().to_str().unwrap_or("N/A"))));
        context.set_val("basename", Value::Str(String::from(dir_entry.file_name().to_str().unwrap_or("N/A"))));
        context.set_val("size", Value::Str(formatter::format_filesize(dir_entry.metadata().unwrap().len(), self.machine_mode)));
        context.set_val("mtime", Value::Str(formatter::format_systime(dir_entry.metadata().unwrap().modified().unwrap(), self.machine_mode)));
        let ctime = match dir_entry.metadata().unwrap().created() {
                Ok(t)   => formatter::format_systime(t, self.machine_mode),
                Err(_)  => String::from("N/A"),
        };
        context.set_val("ctime", Value::Str(ctime));

        let atime = match dir_entry.metadata().unwrap().accessed() {
                Ok(t)   => formatter::format_systime(t, self.machine_mode),
                Err(_)  => String::from("N/A"),
            };
        context.set_val("atime", Value::Str(atime));

        context.set_val("type", Value::Str(formatter::format_filetype(dir_entry.metadata().unwrap().file_type(), self.machine_mode)));
        context.set_val("mimetype", Value::Str(formatter::format_mimetype(mime_guess::guess_mime_type(dir_entry.path().to_str().unwrap_or("N/A")), self.machine_mode)));
        context.set_val("inode", Value::Str(format!("{}", dir_entry.ino())));
        return context;
    }

    fn run_command(&self, dir_entry: &DirEntry) {
        match self.command {
            None    => {},
            Some(ref c) => {
                let template = liquid::parse(c, Default::default()).unwrap();
                let mut context = self.setup_context(dir_entry);
                let output = template.render(&mut context);
                match output {
                    Ok(res) => Command::new("sh").arg("-c").arg(res.unwrap()).spawn().expect("Failed to start command."),
                    Err(e)    => {
                        eprintln!("Command template error: {}", e);
                        process::exit(1);
                    },
                };
            },
        }
    }

    fn raw_walk(&self, dir: &String, max_depth: usize, color_config: &Option<ColorConfig>, color_mode: bool) {
        let dir_iter = WalkDir::new(dir).max_depth(max_depth).into_iter();

        'files: for entry in dir_iter {
            let entry = match entry{
                Ok(e)  => e,
                Err(e) => {
                    eprintln!("Error: {}", e);
                    continue 'files;
                }
            };
            if self.filters.test(&entry) != true {
                    continue 'files;
            }
            self.print_attributes(&entry, color_config, color_mode);
            self.run_command(&entry);
        }
    }

    fn process_entry(&self, entry: Result<DirEntry, walkdir::Error>, color_config: &Option<ColorConfig>, color_mode: bool){
        let entry = match entry{
            Ok(e)  => e,
            Err(e) => {
                eprintln!("Error: {}", e);
                return;
            }
        };
        if self.filters.test(&entry) == true {
            self.print_attributes(&entry, color_config, color_mode);
            self.run_command(&entry);
        }
    }

    fn dev_walk(&self, dir: &String, max_depth: usize, color_config: &Option<ColorConfig>, color_mode: bool, same_device: bool, ignore_hidden: bool){
        let dir_iter = WalkDir::new(dir).max_depth(max_depth).into_iter();

        let dev_id = match WalkDir::new(dir).into_iter().next() {
            Some(e) => {
                let dir_entry = e.expect("Failed to open directory entry.",);
                dir_entry.metadata().map(|m| m.dev()).expect(&format!("Could not get device id from {:?}.", dir_entry))
            }
            None => {
                eprintln!("{} not found!", dir);
                process::exit(1);
            },
        };

        if same_device && ignore_hidden {
            let filtered_iter = dir_iter.filter_entry(|e| e.metadata().map(|m| m.dev() == dev_id).unwrap_or(false))
                                        .filter_entry(|e| !is_hidden(e));
            for entry in filtered_iter {
                self.process_entry(entry, color_config, color_mode);
            }
        } else if same_device {
            let filtered_iter = dir_iter.filter_entry(|e| e.metadata().map(|m| m.dev() == dev_id).unwrap_or(false));
            for entry in filtered_iter {
                self.process_entry(entry, color_config, color_mode);
            }
        } else if ignore_hidden {
            let filtered_iter = dir_iter.filter_entry(|e| !is_hidden(e));
            for entry in filtered_iter {
                self.process_entry(entry, color_config, color_mode);
            }
        } else {
            eprintln!("Implementation error: Use raw_walk instead!");
            process::exit(1);
        }
    }

    pub fn execute(&mut self, max_depth: usize, machine_mode: bool, ignore_hidden: bool, same_device: bool, color: bool, color_config: Option<ColorConfig>) {
        let color_mode = if color {
            stdout_is_tty()
        } else {
            false
        };

        if machine_mode {
            self.machine_mode = true
        }

        for dir in &self.directories {
            if same_device || ignore_hidden {
                self.dev_walk(dir, max_depth, &color_config, color_mode, same_device, ignore_hidden);
            } else {
                self.raw_walk(dir, max_depth, &color_config, color_mode);
            }
        }
    }
}
<|endoftext|>


<commit_before>fn rot13 (string: ~str) -> ~str {
	fn rot13u8 (c: u8) -> u8 {
		match c {
			97..109 => c+13,
			65..77 => c+13,
			110..122 => c-13,
			78..90 => c-13,
			_ => c
		}
	}
        let translated = string.as_bytes().iter().map(|c| rot13u8(*c)).collect();
	std::str::from_utf8_owned(translated).unwrap()
}

fn main () {
	let a =  rot13(~"abc");
	assert_eq!(a, ~"nop");
}
<commit_msg>Added link to rosettacode.org in rot13.rs<commit_after>// Implements http://rosettacode.org/wiki/Rot-13

fn rot13 (string: ~str) -> ~str {
	fn rot13u8 (c: u8) -> u8 {
		match c {
			97..109 => c+13,
			65..77 => c+13,
			110..122 => c-13,
			78..90 => c-13,
			_ => c
		}
	}

    let translated = string.as_bytes().iter().map(|c| rot13u8(*c)).collect();
	std::str::from_utf8_owned(translated).unwrap()
}

fn main () {
	let a =  rot13(~"abc");
	assert_eq!(a, ~"nop");
}
<|endoftext|>


<commit_before>// see DESIGN.md
use std::collections::HashMap;
use std::u16;
use std::sync::Mutex;
use std::fmt;
use std::str::FromStr;

lazy_static! {
    pub static ref SCOPE_REPO: Mutex<ScopeRepository> = Mutex::new(ScopeRepository::new());
}

#[derive(Clone, PartialEq, Eq, Copy)]
pub struct Scope {
    data: [u16; 8],
}

#[derive(Debug)]
pub enum ParseScopeError {
    /// Due to a limitation of the current optimized internal representation
    /// scopes can be at most 8 atoms long
    TooLong,
    /// The internal representation uses 16 bits per atom, so if all scopes ever
    /// used by the program have more than 2^16-2 atoms, things break
    TooManyAtoms,
}

#[derive(Debug)]
pub struct ScopeRepository {
    atoms: Vec<String>,
    atom_index_map: HashMap<String, usize>,
}

fn pack_as_u16s(atoms: &[usize]) -> Result<[u16; 8],ParseScopeError> {
    let mut res: [u16; 8] = [0, 0, 0, 0, 0, 0, 0, 0];

    for i in 0..(atoms.len()) {
        let n = atoms[i];
        if n >= (u16::MAX as usize) - 2 {
            return Err(ParseScopeError::TooManyAtoms);
        }
        let small = (n + 1) as u16; // +1 since we reserve 0 for unused
        res[i] = small;
    }
    Ok(res)
}

impl ScopeRepository {
    fn new() -> ScopeRepository {
        ScopeRepository {
            atoms: Vec::new(),
            atom_index_map: HashMap::new(),
        }
    }

    pub fn build(&mut self, s: &str) -> Result<Scope, ParseScopeError> {
        let parts: Vec<usize> = s.split('.').map(|a| self.atom_to_index(a)).collect();
        if parts.len() > 8 {
            return Err(ParseScopeError::TooManyAtoms);
        }
        Ok(Scope { data: try!(pack_as_u16s(&parts[..])) })
    }

    pub fn to_string(&self, scope: Scope) -> String {
        let mut s = String::new();
        for i in 0..8 {
            let atom_number = scope.data[i];
            if atom_number == 0 {
                break;
            }
            if i != 0 {
                s.push_str(".");
            }
            s.push_str(&self.atoms[(atom_number - 1) as usize]);
        }
        s
    }

    fn atom_to_index(&mut self, atom: &str) -> usize {
        if let Some(index) = self.atom_index_map.get(atom) {
            return *index;
        }
        self.atoms.push(atom.to_owned());
        let index = self.atoms.len() - 1;
        self.atom_index_map.insert(atom.to_owned(), index);
        return index;
    }
}

impl Scope {
    pub fn new(s: &str) -> Result<Scope, ParseScopeError> {
        let mut repo = SCOPE_REPO.lock().unwrap();
        repo.build(s.trim())
    }
}

impl FromStr for Scope {
    type Err = ParseScopeError;

    fn from_str(s: &str) -> Result<Scope, ParseScopeError> {
        Scope::new(s)
    }
}

impl fmt::Display for Scope {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let repo = SCOPE_REPO.lock().unwrap();
        let s = repo.to_string(*self);
        write!(f, "{}", s)
    }
}

impl fmt::Debug for Scope {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let repo = SCOPE_REPO.lock().unwrap();
        let s = repo.to_string(*self);
        write!(f, "<{}>", s)
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScopeStack {
    scopes: Vec<Scope>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ScopeStackOp {
    Push(Scope),
    Pop(usize),
}

impl ScopeStack {
    pub fn new() -> ScopeStack {
        ScopeStack { scopes: Vec::new() }
    }
    pub fn push(&mut self, s: Scope) {
        self.scopes.push(s);
    }
    pub fn apply(&mut self, op: &ScopeStackOp) {
        match op {
            &ScopeStackOp::Push(scope) => self.scopes.push(scope),
            &ScopeStackOp::Pop(count) => {
                for _ in 0..count {
                    self.scopes.pop();
                }
            }
        }
    }
    pub fn debug_print(&self, repo: &ScopeRepository) {
        for s in self.scopes.iter() {
            print!("{} ", repo.to_string(*s));
        }
        println!("");
    }
}

impl FromStr for ScopeStack {
    type Err = ParseScopeError;

    fn from_str(s: &str) -> Result<ScopeStack, ParseScopeError> {
        let mut scopes = Vec::new();
        for name in s.split_whitespace() {
            scopes.push(try!(Scope::from_str(name)))
        };
        Ok(ScopeStack {scopes: scopes})
    }
}

impl fmt::Display for ScopeStack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for s in self.scopes.iter() {
            try!(write!(f, "{} ", s));
        }
        Ok(())
    }
}

// The following code (until the tests module at the end)
// is based on code from https://github.com/defuz/sublimate/blob/master/src/core/syntax/scope.rs
// under the MIT license

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScopeSelector {
    path: ScopeStack,
    exclude: Option<ScopeStack>
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScopeSelectors {
    pub selectors: Vec<ScopeSelector>
}

impl FromStr for ScopeSelector {
    type Err = ParseScopeError;

    fn from_str(s: &str) -> Result<ScopeSelector, ParseScopeError> {
        match s.find(" - ") {
            Some(index) => {
                let (path_str, exclude_str) = s.split_at(index);
                Ok(ScopeSelector {
                    path: try!(ScopeStack::from_str(path_str)),
                    exclude: Some(try!(ScopeStack::from_str(exclude_str))),
                })
            },
            None => {
                Ok(ScopeSelector {
                    path: try!(ScopeStack::from_str(s)),
                    exclude: None,
                })
            }
        }
    }
}

impl FromStr for ScopeSelectors {
    type Err = ParseScopeError;

    fn from_str(s: &str) -> Result<ScopeSelectors, ParseScopeError> {
        let mut selectors = Vec::new();
        for selector in s.split(',') {
            selectors.push(try!(ScopeSelector::from_str(selector)))
        };
        Ok(ScopeSelectors {
            selectors: selectors
        })
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn misc() {
        // use std::mem;
        // use std::rc::{Rc};
        // use scope::*;
        // assert_eq!(8, mem::size_of::<Rc<Scope>>());
        // assert_eq!(Scope::new("source.php"), Scope::new("source.php"));
    }
    #[test]
    fn repo_works() {
        use scope::*;
        let mut repo = ScopeRepository::new();
        assert_eq!(repo.build("source.php").unwrap(), repo.build("source.php").unwrap());
        assert_eq!(repo.build("source.php.wow.hi.bob.troll.clock.5").unwrap(),
                   repo.build("source.php.wow.hi.bob.troll.clock.5").unwrap());
        assert_eq!(repo.build("").unwrap(), repo.build("").unwrap());
        let s1 = repo.build("").unwrap();
        assert_eq!(repo.to_string(s1), "");
        let s2 = repo.build("source.php.wow").unwrap();
        assert_eq!(repo.to_string(s2), "source.php.wow");
        assert!(repo.build("source.php").unwrap() != repo.build("source.perl").unwrap());
        assert!(repo.build("source.php").unwrap() != repo.build("source.php.wagon").unwrap());
    }
}
<commit_msg>Add tests and fix bug with new scope stuff<commit_after>// see DESIGN.md
use std::collections::HashMap;
use std::u16;
use std::sync::Mutex;
use std::fmt;
use std::str::FromStr;

lazy_static! {
    pub static ref SCOPE_REPO: Mutex<ScopeRepository> = Mutex::new(ScopeRepository::new());
}

#[derive(Clone, PartialEq, Eq, Copy)]
pub struct Scope {
    data: [u16; 8],
}

#[derive(Debug)]
pub enum ParseScopeError {
    /// Due to a limitation of the current optimized internal representation
    /// scopes can be at most 8 atoms long
    TooLong,
    /// The internal representation uses 16 bits per atom, so if all scopes ever
    /// used by the program have more than 2^16-2 atoms, things break
    TooManyAtoms,
}

#[derive(Debug)]
pub struct ScopeRepository {
    atoms: Vec<String>,
    atom_index_map: HashMap<String, usize>,
}

fn pack_as_u16s(atoms: &[usize]) -> Result<[u16; 8],ParseScopeError> {
    let mut res: [u16; 8] = [0, 0, 0, 0, 0, 0, 0, 0];

    for i in 0..(atoms.len()) {
        let n = atoms[i];
        if n >= (u16::MAX as usize) - 2 {
            return Err(ParseScopeError::TooManyAtoms);
        }
        let small = (n + 1) as u16; // +1 since we reserve 0 for unused
        res[i] = small;
    }
    Ok(res)
}

impl ScopeRepository {
    fn new() -> ScopeRepository {
        ScopeRepository {
            atoms: Vec::new(),
            atom_index_map: HashMap::new(),
        }
    }

    pub fn build(&mut self, s: &str) -> Result<Scope, ParseScopeError> {
        let parts: Vec<usize> = s.split('.').map(|a| self.atom_to_index(a)).collect();
        if parts.len() > 8 {
            return Err(ParseScopeError::TooManyAtoms);
        }
        Ok(Scope { data: try!(pack_as_u16s(&parts[..])) })
    }

    pub fn to_string(&self, scope: Scope) -> String {
        let mut s = String::new();
        for i in 0..8 {
            let atom_number = scope.data[i];
            if atom_number == 0 {
                break;
            }
            if i != 0 {
                s.push_str(".");
            }
            s.push_str(&self.atoms[(atom_number - 1) as usize]);
        }
        s
    }

    fn atom_to_index(&mut self, atom: &str) -> usize {
        if let Some(index) = self.atom_index_map.get(atom) {
            return *index;
        }
        self.atoms.push(atom.to_owned());
        let index = self.atoms.len() - 1;
        self.atom_index_map.insert(atom.to_owned(), index);
        return index;
    }
}

impl Scope {
    pub fn new(s: &str) -> Result<Scope, ParseScopeError> {
        let mut repo = SCOPE_REPO.lock().unwrap();
        repo.build(s.trim())
    }
}

impl FromStr for Scope {
    type Err = ParseScopeError;

    fn from_str(s: &str) -> Result<Scope, ParseScopeError> {
        Scope::new(s)
    }
}

impl fmt::Display for Scope {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let repo = SCOPE_REPO.lock().unwrap();
        let s = repo.to_string(*self);
        write!(f, "{}", s)
    }
}

impl fmt::Debug for Scope {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let repo = SCOPE_REPO.lock().unwrap();
        let s = repo.to_string(*self);
        write!(f, "<{}>", s)
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScopeStack {
    scopes: Vec<Scope>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ScopeStackOp {
    Push(Scope),
    Pop(usize),
}

impl ScopeStack {
    pub fn new() -> ScopeStack {
        ScopeStack { scopes: Vec::new() }
    }
    pub fn push(&mut self, s: Scope) {
        self.scopes.push(s);
    }
    pub fn apply(&mut self, op: &ScopeStackOp) {
        match op {
            &ScopeStackOp::Push(scope) => self.scopes.push(scope),
            &ScopeStackOp::Pop(count) => {
                for _ in 0..count {
                    self.scopes.pop();
                }
            }
        }
    }
    pub fn debug_print(&self, repo: &ScopeRepository) {
        for s in self.scopes.iter() {
            print!("{} ", repo.to_string(*s));
        }
        println!("");
    }
}

impl FromStr for ScopeStack {
    type Err = ParseScopeError;

    fn from_str(s: &str) -> Result<ScopeStack, ParseScopeError> {
        let mut scopes = Vec::new();
        for name in s.split_whitespace() {
            scopes.push(try!(Scope::from_str(name)))
        };
        Ok(ScopeStack {scopes: scopes})
    }
}

impl fmt::Display for ScopeStack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for s in self.scopes.iter() {
            try!(write!(f, "{} ", s));
        }
        Ok(())
    }
}

// The following code (until the tests module at the end)
// is based on code from https://github.com/defuz/sublimate/blob/master/src/core/syntax/scope.rs
// under the MIT license

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScopeSelector {
    path: ScopeStack,
    exclude: Option<ScopeStack>
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScopeSelectors {
    pub selectors: Vec<ScopeSelector>
}

impl FromStr for ScopeSelector {
    type Err = ParseScopeError;

    fn from_str(s: &str) -> Result<ScopeSelector, ParseScopeError> {
        match s.find(" - ") {
            Some(index) => {
                let (path_str, exclude_with_dash) = s.split_at(index);
                let exclude_str = &exclude_with_dash[3..];
                Ok(ScopeSelector {
                    path: try!(ScopeStack::from_str(path_str)),
                    exclude: Some(try!(ScopeStack::from_str(exclude_str))),
                })
            },
            None => {
                Ok(ScopeSelector {
                    path: try!(ScopeStack::from_str(s)),
                    exclude: None,
                })
            }
        }
    }
}

impl FromStr for ScopeSelectors {
    type Err = ParseScopeError;

    fn from_str(s: &str) -> Result<ScopeSelectors, ParseScopeError> {
        let mut selectors = Vec::new();
        for selector in s.split(',') {
            selectors.push(try!(ScopeSelector::from_str(selector)))
        };
        Ok(ScopeSelectors {
            selectors: selectors
        })
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn misc() {
        // use std::mem;
        // use std::rc::{Rc};
        // use scope::*;
        // assert_eq!(8, mem::size_of::<Rc<Scope>>());
        // assert_eq!(Scope::new("source.php"), Scope::new("source.php"));
    }
    #[test]
    fn repo_works() {
        use scope::*;
        let mut repo = ScopeRepository::new();
        assert_eq!(repo.build("source.php").unwrap(), repo.build("source.php").unwrap());
        assert_eq!(repo.build("source.php.wow.hi.bob.troll.clock.5").unwrap(),
                   repo.build("source.php.wow.hi.bob.troll.clock.5").unwrap());
        assert_eq!(repo.build("").unwrap(), repo.build("").unwrap());
        let s1 = repo.build("").unwrap();
        assert_eq!(repo.to_string(s1), "");
        let s2 = repo.build("source.php.wow").unwrap();
        assert_eq!(repo.to_string(s2), "source.php.wow");
        assert!(repo.build("source.php").unwrap() != repo.build("source.perl").unwrap());
        assert!(repo.build("source.php").unwrap() != repo.build("source.php.wagon").unwrap());
    }
    #[test]
    fn global_repo_works() {
        use scope::*;
        use std::str::FromStr;
        assert_eq!(Scope::new("source.php").unwrap(), Scope::new("source.php").unwrap());
        assert!(Scope::from_str("1.2.3.4.5.6.7.8").is_ok());
        assert!(Scope::from_str("1.2.3.4.5.6.7.8.9").is_err());
    }
    #[test]
    fn selectors_work() {
        use scope::*;
        use std::str::FromStr;
        let sels = ScopeSelectors::from_str("source.php meta.preprocessor - string.quoted, source string").unwrap();
        assert_eq!(sels.selectors.len(), 2);
        let first_sel = &sels.selectors[0];
        assert_eq!(format!("{:?}", first_sel),
            "ScopeSelector { path: ScopeStack { scopes: [<source.php>, <meta.preprocessor>] }, exclude: Some(ScopeStack { scopes: [<string.quoted>] }) }");
    }
}
<|endoftext|>


<commit_before>use std::cmp::min;

#[derive(Debug)]
#[derive(PartialEq)]
pub struct Quality(pub f32);

#[derive(Debug)]
#[derive(PartialEq)]
pub struct Substring(pub usize,pub usize);

#[derive(Debug)]
#[derive(PartialEq)]
pub struct Match<'a> {
    pub quality: Quality,
    pub range: Substring,
    pub original: &'a String,

}

impl <'a>Match<'a>{
    pub fn new(quality: Quality, range: Substring, original: &'a String) -> Match<'a> {
        Match { quality: quality, range: range, original: original }
    }
}

pub fn score<'a>(choice: &'a String, query: &String) -> Option<Match<'a>> {
    let choice_length = choice.len() as f32;
    let query_length = query.len() as f32;

    if query_length == 0.0 { return Some(Match::new(Quality(1.0), Substring(0,0), choice)) }

    match new_compute_match_length(choice, query) {
        Some((start, match_length)) => {
            let quality = Quality( (query_length / match_length as f32) / choice_length);
            let substring = Substring(start, start+match_length);
            Some(Match::new(quality, substring, choice))
        },
        None => None,
    }
}

fn new_compute_match_length(choice: &String, query: &String) -> Option<(usize, usize)> {
    if query.len() == 0 {
        return None;
    }
    let (first, rest) = query.slice_shift_char().unwrap();

    let impossible_match = choice.len() + 1;
    let mut shortest_match = impossible_match;
    let mut shortest_start = impossible_match;

    for_each_beginning(choice, first, |beginning| {
        match match_length_from(choice, rest, beginning) {
            Some(length) => {
                             shortest_match = min(length, shortest_match);
                             shortest_start = beginning;
            },
            None => {},
        };
    });

    if shortest_match == impossible_match {None} else {Some((shortest_start, shortest_match))}
}

fn for_each_beginning<F: FnMut(usize)>(choice: &String, beginning: char, mut f: F) {
    for (idx, character) in choice.chars().enumerate() {
        if character == beginning {
            f(idx);
        }
    }
}

fn match_length_from(choice: &String, query: &str, beginning: usize) -> Option<usize> {
    let mut match_index = beginning;

    for query_char in query.chars() {
       match find_first_after(choice, query_char, match_index + 1) {
           Some(n) => match_index = n,
           None => return None,
       };
    }
    Some(match_index - beginning + 1)
}

fn find_first_after(choice: &String, query: char, offset: usize) -> Option<usize> {
    choice[offset..]
        .find(query)
        .map(|index| index + offset)
}
<commit_msg>Renames new_compute_match... to just compute_match..<commit_after>use std::cmp::min;

#[derive(Debug)]
#[derive(PartialEq)]
pub struct Quality(pub f32);

#[derive(Debug)]
#[derive(PartialEq)]
pub struct Substring(pub usize,pub usize);

#[derive(Debug)]
#[derive(PartialEq)]
pub struct Match<'a> {
    pub quality: Quality,
    pub range: Substring,
    pub original: &'a String,

}

impl <'a>Match<'a>{
    pub fn new(quality: Quality, range: Substring, original: &'a String) -> Match<'a> {
        Match { quality: quality, range: range, original: original }
    }
}

pub fn score<'a>(choice: &'a String, query: &String) -> Option<Match<'a>> {
    let choice_length = choice.len() as f32;
    let query_length = query.len() as f32;

    if query_length == 0.0 { return Some(Match::new(Quality(1.0), Substring(0,0), choice)) }

    match compute_match_length(choice, query) {
        Some((start, match_length)) => {
            let quality = Quality( (query_length / match_length as f32) / choice_length);
            let substring = Substring(start, start+match_length);
            Some(Match::new(quality, substring, choice))
        },
        None => None,
    }
}

fn compute_match_length(choice: &String, query: &String) -> Option<(usize, usize)> {
    if query.len() == 0 {
        return None;
    }
    let (first, rest) = query.slice_shift_char().unwrap();

    let impossible_match = choice.len() + 1;
    let mut shortest_match = impossible_match;
    let mut shortest_start = impossible_match;

    for_each_beginning(choice, first, |beginning| {
        match match_length_from(choice, rest, beginning) {
            Some(length) => {
                             shortest_match = min(length, shortest_match);
                             shortest_start = beginning;
            },
            None => {},
        };
    });

    if shortest_match == impossible_match {None} else {Some((shortest_start, shortest_match))}
}

fn for_each_beginning<F: FnMut(usize)>(choice: &String, beginning: char, mut f: F) {
    for (idx, character) in choice.chars().enumerate() {
        if character == beginning {
            f(idx);
        }
    }
}

fn match_length_from(choice: &String, query: &str, beginning: usize) -> Option<usize> {
    let mut match_index = beginning;

    for query_char in query.chars() {
       match find_first_after(choice, query_char, match_index + 1) {
           Some(n) => match_index = n,
           None => return None,
       };
    }
    Some(match_index - beginning + 1)
}

fn find_first_after(choice: &String, query: char, offset: usize) -> Option<usize> {
    choice[offset..]
        .find(query)
        .map(|index| index + offset)
}
<|endoftext|>


<commit_before>extern crate serde;
extern crate std;

use self::std::fmt;
use self::std::prelude::v1::*;
use self::serde::{de, Deserialize, Deserializer, Serialize, Serializer};

use Uuid;

impl Serialize for Uuid {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_str(&self.hyphenated().to_string())
    }
}

impl<'de> Deserialize<'de> for Uuid {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        struct UuidVisitor;

        impl<'vi> de::Visitor<'vi> for UuidVisitor {
            type Value = Uuid;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(formatter, "a UUID string")
            }

            fn visit_str<E: de::Error>(self, value: &str) -> Result<Uuid, E> {
                value.parse::<Uuid>().map_err(|e| E::custom(e.to_string()))
            }
        }

        deserializer.deserialize_str(UuidVisitor)
    }
}
<commit_msg>Try to avoid allocating a String when serializing<commit_after>extern crate serde;
extern crate std;

use self::std::fmt;
use self::std::prelude::v1::*;
use self::serde::{de, Deserialize, Deserializer, Serialize, Serializer};

use Uuid;

impl Serialize for Uuid {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.collect_str(&self.hyphenated())
    }
}

impl<'de> Deserialize<'de> for Uuid {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        struct UuidVisitor;

        impl<'vi> de::Visitor<'vi> for UuidVisitor {
            type Value = Uuid;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(formatter, "a UUID string")
            }

            fn visit_str<E: de::Error>(self, value: &str) -> Result<Uuid, E> {
                value.parse::<Uuid>().map_err(|e| E::custom(e.to_string()))
            }
        }

        deserializer.deserialize_str(UuidVisitor)
    }
}
<|endoftext|>


<commit_before>pub struct Space {
    state: SpaceState,
    position: [u8; 2],
}

impl Space {
    pub fn new(pos: [u8; 2]) -> Space {
        Space {
            state: SpaceState::Unchecked,
            position: pos,
        }
    }

    pub fn all_grid_spaces(grid_size: &[u8; 2]) -> Vec<Space> {
        let x = grid_size[0] as usize;
        let y = grid_size[1] as usize;
        let mut spaces = Vec::with_capacity(x * y);

        for col in 0..grid_size[0] {
            for row in 0..grid_size[1] {
                spaces.push(Space::new([col, row]));
            }
        }

        spaces
    }

    /// Sets this space as having been checked, and whether it was hit.
    ///
    /// # Errors
    ///
    /// Returns an error if the space's state is not `SpaceState::Unchecked`.
    pub fn set_checked(&mut self, hit: bool) -> Result<(), &'static str> {
        if self.state != SpaceState::Unchecked {
            Err("tried to check an already checked space")
        } else {
            self.state = SpaceState::Checked(hit);
            Ok(())
        }
    }

    pub fn is_unchecked(&self) -> bool {
        self.state == SpaceState::Unchecked
    }

    pub fn is_empty(&self) -> bool {
        self.state == SpaceState::Checked(false)
    }

    pub fn is_hit(&self) -> bool {
        self.state == SpaceState::Checked(true)
    }

    pub fn pos(&self) -> &[u8; 2] {
        &self.position
    }
}

#[derive(Clone, Copy, PartialEq)]
pub enum SpaceState {
    Unchecked,
    Checked(bool),
}

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

    #[test]
    fn set_checked() {
        let mut space = Space::new([0, 0]);
        assert!(space.set_checked(false).is_ok());
        assert!(space.set_checked(false).is_err());

        space = Space::new([0, 0]);
        assert!(space.set_checked(true).is_ok());
        assert!(space.set_checked(true).is_err());
    }

    #[test]
    fn is_unchecked() {
        let mut space = Space::new([0, 0]);
        assert!(space.is_unchecked());
        assert!(space.set_checked(false).is_ok());
        assert!(!space.is_unchecked());

        space = Space::new([0, 0]);
        assert!(space.set_checked(true).is_ok());
        assert!(!space.is_unchecked());
    }

    #[test]
    fn is_empty() {
        let mut space = Space::new([0, 0]);
        assert!(!space.is_empty());
        assert!(space.set_checked(false).is_ok());
        assert!(space.is_empty());

        space = Space::new([0, 0]);
        assert!(space.set_checked(true).is_ok());
        assert!(!space.is_empty());
    }

    #[test]
    fn is_hit() {
        let mut space = Space::new([0, 0]);
        assert!(!space.is_hit());
        assert!(space.set_checked(true).is_ok());
        assert!(space.is_hit());

        space = Space::new([0, 0]);
        assert!(space.set_checked(false).is_ok());
        assert!(!space.is_hit());
    }

    #[test]
    fn pos() {
        let space = Space::new([0, 0]);
        assert_eq!(space.pos(), &[0, 0]);
    }
}
<commit_msg>Create all grid spaces with flat_map()<commit_after>pub struct Space {
    state: SpaceState,
    position: [u8; 2],
}

impl Space {
    pub fn new(pos: [u8; 2]) -> Space {
        Space {
            state: SpaceState::Unchecked,
            position: pos,
        }
    }

    pub fn all_grid_spaces(grid_size: &[u8; 2]) -> Vec<Space> {
        (0..grid_size[0])
            .flat_map(|col| (0..grid_size[1]).map(move |row| Space::new([col, row])))
            .collect()
    }

    /// Sets this space as having been checked, and whether it was hit.
    ///
    /// # Errors
    ///
    /// Returns an error if the space's state is not `SpaceState::Unchecked`.
    pub fn set_checked(&mut self, hit: bool) -> Result<(), &'static str> {
        if self.state != SpaceState::Unchecked {
            Err("tried to check an already checked space")
        } else {
            self.state = SpaceState::Checked(hit);
            Ok(())
        }
    }

    pub fn is_unchecked(&self) -> bool {
        self.state == SpaceState::Unchecked
    }

    pub fn is_empty(&self) -> bool {
        self.state == SpaceState::Checked(false)
    }

    pub fn is_hit(&self) -> bool {
        self.state == SpaceState::Checked(true)
    }

    pub fn pos(&self) -> &[u8; 2] {
        &self.position
    }
}

#[derive(Clone, Copy, PartialEq)]
pub enum SpaceState {
    Unchecked,
    Checked(bool),
}

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

    #[test]
    fn set_checked() {
        let mut space = Space::new([0, 0]);
        assert!(space.set_checked(false).is_ok());
        assert!(space.set_checked(false).is_err());

        space = Space::new([0, 0]);
        assert!(space.set_checked(true).is_ok());
        assert!(space.set_checked(true).is_err());
    }

    #[test]
    fn is_unchecked() {
        let mut space = Space::new([0, 0]);
        assert!(space.is_unchecked());
        assert!(space.set_checked(false).is_ok());
        assert!(!space.is_unchecked());

        space = Space::new([0, 0]);
        assert!(space.set_checked(true).is_ok());
        assert!(!space.is_unchecked());
    }

    #[test]
    fn is_empty() {
        let mut space = Space::new([0, 0]);
        assert!(!space.is_empty());
        assert!(space.set_checked(false).is_ok());
        assert!(space.is_empty());

        space = Space::new([0, 0]);
        assert!(space.set_checked(true).is_ok());
        assert!(!space.is_empty());
    }

    #[test]
    fn is_hit() {
        let mut space = Space::new([0, 0]);
        assert!(!space.is_hit());
        assert!(space.set_checked(true).is_ok());
        assert!(space.is_hit());

        space = Space::new([0, 0]);
        assert!(space.set_checked(false).is_ok());
        assert!(!space.is_hit());
    }

    #[test]
    fn pos() {
        let space = Space::new([0, 0]);
        assert_eq!(space.pos(), &[0, 0]);
    }
}
<|endoftext|>