<commit_before>use std::borrow::Cow;
use std::cmp::Ordering;
use std::fmt::{self, Display};
use std::hash::{Hash, Hasher};

use proc_macro2::Term;
use unicode_xid::UnicodeXID;

use Span;
use tokens;

/// A word of Rust code, such as a keyword or variable name.
///
/// An identifier consists of at least one Unicode code point, the first of
/// which has the XID_Start property and the rest of which have the XID_Continue
/// property. An underscore may be used as the first character as long as it is
/// not the only character.
///
/// - The empty string is not an identifier. Use `Option<Ident>`.
/// - An underscore by itself is not an identifier. Use
///   `syn::tokens::Underscore` instead.
/// - A lifetime is not an identifier. Use `syn::Lifetime` instead.
///
/// An identifier constructed with `Ident::new` is permitted to be a Rust
/// keyword, though parsing an identifier with `syn!(Ident)` rejects Rust
/// keywords.
#[derive(Copy, Clone, Debug)]
pub struct Ident {
    pub sym: Term,
    pub span: Span,
}

impl Ident {
    pub fn new(sym: Term, span: Span) -> Self {
        let s = sym.as_str();

        if s.is_empty() {
            panic!("ident is not allowed to be empty; use Option<Ident>");
        }

        if s.starts_with('\'') {
            panic!("ident is not allowed to be a lifetime; use syn::Lifetime");
        }

        if s == "_" {
            panic!("`_` is not a valid ident; use syn::tokens::Underscore");
        }

        fn xid_ok(s: &str) -> bool {
            let mut chars = s.chars();
            let first = chars.next().unwrap();
            if !(UnicodeXID::is_xid_start(first) || first == '_') {
                return false;
            }
            for ch in chars {
                if !UnicodeXID::is_xid_continue(ch) {
                    return false;
                }
            }
            true
        }

        fn integer_ok(s: &str) -> bool {
            s.bytes().all(|digit| digit >= b'0' && digit <= b'9')
        }

        if !(xid_ok(s) || integer_ok(s)) {
            panic!("{:?} is not a valid ident", s);
        }

        Ident {
            sym: sym,
            span: span,
        }
    }
}

impl<'a> From<&'a str> for Ident {
    fn from(s: &str) -> Self {
        Ident::new(Term::intern(s), Span::default())
    }
}

impl From<tokens::Self_> for Ident {
    fn from(tok: tokens::Self_) -> Self {
        Ident::new(Term::intern("self"), tok.0)
    }
}

impl From<tokens::CapSelf> for Ident {
    fn from(tok: tokens::CapSelf) -> Self {
        Ident::new(Term::intern("Self"), tok.0)
    }
}

impl From<tokens::Super> for Ident {
    fn from(tok: tokens::Super) -> Self {
        Ident::new(Term::intern("super"), tok.0)
    }
}

impl<'a> From<Cow<'a, str>> for Ident {
    fn from(s: Cow<'a, str>) -> Self {
        Ident::new(Term::intern(&s), Span::default())
    }
}

impl From<String> for Ident {
    fn from(s: String) -> Self {
        Ident::new(Term::intern(&s), Span::default())
    }
}

impl AsRef<str> for Ident {
    fn as_ref(&self) -> &str {
        self.sym.as_str()
    }
}

impl Display for Ident {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.sym.as_str().fmt(formatter)
    }
}

impl<T: ?Sized> PartialEq<T> for Ident
    where T: AsRef<str>
{
    fn eq(&self, other: &T) -> bool {
        self.as_ref() == other.as_ref()
    }
}

impl Eq for Ident {}

impl PartialOrd for Ident {
    fn partial_cmp(&self, other: &Ident) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Ident {
    fn cmp(&self, other: &Ident) -> Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

impl Hash for Ident {
    fn hash<H: Hasher>(&self, h: &mut H) {
        self.as_ref().hash(h)
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use synom::{Synom, PResult, Cursor, parse_error};

    impl Synom for Ident {
        fn parse(input: Cursor) -> PResult<Self> {
            let (rest, span, sym) = match input.word() {
                Some(word) => word,
                _ => return parse_error(),
            };
            if sym.as_str().starts_with('\'') {
                return parse_error();
            }
            match sym.as_str() {
                // From https://doc.rust-lang.org/grammar.html#keywords
                "abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue" |
                "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" |
                "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" |
                "mut" | "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" |
                "return" | "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" |
                "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" |
                "while" | "yield" => return parse_error(),
                _ => {}
            }

            Ok((rest, Ident {
                span: Span(span),
                sym: sym,
            }))
        }

        fn description() -> Option<&'static str> {
            Some("identifier")
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};
    use proc_macro2::{TokenTree, TokenNode};

    impl ToTokens for Ident {
        fn to_tokens(&self, tokens: &mut Tokens) {
            tokens.append(TokenTree {
                span: self.span.0,
                kind: TokenNode::Term(self.sym),
            })
        }
    }
}
<commit_msg>Add examples to Ident<commit_after>use std::borrow::Cow;
use std::cmp::Ordering;
use std::fmt::{self, Display};
use std::hash::{Hash, Hasher};

use proc_macro2::Term;
use unicode_xid::UnicodeXID;

use Span;
use tokens;

/// A word of Rust code, such as a keyword or variable name.
///
/// An identifier consists of at least one Unicode code point, the first of
/// which has the XID_Start property and the rest of which have the XID_Continue
/// property. An underscore may be used as the first character as long as it is
/// not the only character.
///
/// - The empty string is not an identifier. Use `Option<Ident>`.
/// - An underscore by itself is not an identifier. Use
///   `syn::tokens::Underscore` instead.
/// - A lifetime is not an identifier. Use `syn::Lifetime` instead.
///
/// An identifier constructed with `Ident::new` is permitted to be a Rust
/// keyword, though parsing input with [`parse`], [`parse_str`] or
/// [`parse_tokens`] rejects Rust keywords.
///
/// [`parse`]: fn.parse.html
/// [`parse_str`]: fn.parse_str.html
/// [`parse_tokens`]: fn.parse_tokens.html
///
/// # Examples
///
/// A new ident can be created from a string using the `Ident::from` function.
///
/// ```rust
/// extern crate syn;
/// use syn::Ident;
/// #
/// # fn main() {
///
/// let ident = Ident::from("another_identifier");
///
/// # }
/// ```
///
/// When the ident is used in Macros 1.1 output, it needs to be turned into
/// a token stream. This is easy to do using the `quote!` macro from the `quote`
/// crate.
///
/// ```rust
/// # #[macro_use]
/// # extern crate quote;
/// # extern crate syn;
/// # use syn::Ident;
/// # fn main() {
/// # let ident = Ident::from("another_identifier");
/// #
/// // Create tokens using the ident.
/// let expanded = quote! { let #ident = 10; };
///
/// // Derive a new ident from the existing one.
/// let temp_ident = Ident::from(format!("new_{}", ident));
/// let expanded = quote! { let $temp_ident = 10; };
///
/// # }
/// ```
///
/// If `syn` is used to parse existing Rust source code, it is often useful to
/// convert the `Ident` to a more generic string data type at some point. The
/// methods `as_ref()` and `to_string()` achieve this.
///
/// ```rust
/// # use syn::Ident;
/// # let ident = Ident::from("another_identifier");
/// #
/// // Examine the ident as a &str.
/// let ident_str = ident.as_ref();
/// if ident_str.len() > 60 {
///     println!("Very long identifier: {}", ident_str)
/// }
///
/// // Create a String from the ident.
/// let ident_string = ident.to_string();
/// give_away(ident_string);
///
/// fn give_away(s: String) { /* ... */ }
/// ```
#[derive(Copy, Clone, Debug)]
pub struct Ident {
    pub sym: Term,
    pub span: Span,
}

impl Ident {

    /// Creates a new `Ident` from the structured items. This is mainly used
    /// by the parser to create `Ident`s from existing Rust source code.
    ///
    /// Creating new `Ident`s programmatically is easier with `Ident::from`.
    pub fn new(sym: Term, span: Span) -> Self {
        let s = sym.as_str();

        if s.is_empty() {
            panic!("ident is not allowed to be empty; use Option<Ident>");
        }

        if s.starts_with('\'') {
            panic!("ident is not allowed to be a lifetime; use syn::Lifetime");
        }

        if s == "_" {
            panic!("`_` is not a valid ident; use syn::tokens::Underscore");
        }

        fn xid_ok(s: &str) -> bool {
            let mut chars = s.chars();
            let first = chars.next().unwrap();
            if !(UnicodeXID::is_xid_start(first) || first == '_') {
                return false;
            }
            for ch in chars {
                if !UnicodeXID::is_xid_continue(ch) {
                    return false;
                }
            }
            true
        }

        fn integer_ok(s: &str) -> bool {
            s.bytes().all(|digit| digit >= b'0' && digit <= b'9')
        }

        if !(xid_ok(s) || integer_ok(s)) {
            panic!("{:?} is not a valid ident", s);
        }

        Ident {
            sym: sym,
            span: span,
        }
    }
}

impl<'a> From<&'a str> for Ident {
    fn from(s: &str) -> Self {
        Ident::new(Term::intern(s), Span::default())
    }
}

impl From<tokens::Self_> for Ident {
    fn from(tok: tokens::Self_) -> Self {
        Ident::new(Term::intern("self"), tok.0)
    }
}

impl From<tokens::CapSelf> for Ident {
    fn from(tok: tokens::CapSelf) -> Self {
        Ident::new(Term::intern("Self"), tok.0)
    }
}

impl From<tokens::Super> for Ident {
    fn from(tok: tokens::Super) -> Self {
        Ident::new(Term::intern("super"), tok.0)
    }
}

impl<'a> From<Cow<'a, str>> for Ident {
    fn from(s: Cow<'a, str>) -> Self {
        Ident::new(Term::intern(&s), Span::default())
    }
}

impl From<String> for Ident {
    fn from(s: String) -> Self {
        Ident::new(Term::intern(&s), Span::default())
    }
}

impl AsRef<str> for Ident {
    fn as_ref(&self) -> &str {
        self.sym.as_str()
    }
}

impl Display for Ident {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.sym.as_str().fmt(formatter)
    }
}

impl<T: ?Sized> PartialEq<T> for Ident
    where T: AsRef<str>
{
    fn eq(&self, other: &T) -> bool {
        self.as_ref() == other.as_ref()
    }
}

impl Eq for Ident {}

impl PartialOrd for Ident {
    fn partial_cmp(&self, other: &Ident) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Ident {
    fn cmp(&self, other: &Ident) -> Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

impl Hash for Ident {
    fn hash<H: Hasher>(&self, h: &mut H) {
        self.as_ref().hash(h)
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use synom::{Synom, PResult, Cursor, parse_error};

    impl Synom for Ident {
        fn parse(input: Cursor) -> PResult<Self> {
            let (rest, span, sym) = match input.word() {
                Some(word) => word,
                _ => return parse_error(),
            };
            if sym.as_str().starts_with('\'') {
                return parse_error();
            }
            match sym.as_str() {
                // From https://doc.rust-lang.org/grammar.html#keywords
                "abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue" |
                "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" |
                "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" |
                "mut" | "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" |
                "return" | "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" |
                "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" |
                "while" | "yield" => return parse_error(),
                _ => {}
            }

            Ok((rest, Ident {
                span: Span(span),
                sym: sym,
            }))
        }

        fn description() -> Option<&'static str> {
            Some("identifier")
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};
    use proc_macro2::{TokenTree, TokenNode};

    impl ToTokens for Ident {
        fn to_tokens(&self, tokens: &mut Tokens) {
            tokens.append(TokenTree {
                span: self.span.0,
                kind: TokenNode::Term(self.sym),
            })
        }
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::fs::{PathExt, DirEntry};
use std::path::{Path, PathBuf};
use std::io::Error;

pub struct Index {
    path: PathBuf,
    entries: Vec<PathBuf>,
}

impl Index {
    /// Finds all files inside and beneath the index path
    /// and adds them to the index entries vector.
    pub fn populate(&mut self) {
        // The entries listed by read_dir include the root index path; we want
        // relative paths, so we get this length so that we can strip it.
        let prefix_length = match self.path.to_str() {
            Some(path) => path.len()+1,
            None => return,
        };

        // Start by getting any files in the root path. Since
        // read_directory_entries is already borrowing a mutable
        // reference to the index, so we can't also lend out a
        // reference to its path field, hence the clone.
        let path = self.path.clone();
        self.index_directory_files(&path, prefix_length);

        // Get an iterator that'll let us walk all of the subdirectories
        // of the index path, bailing out if there's an error of any kind.
        match fs::walk_dir(&self.path) {
            Ok(subdirectories) => {
                // Index any other files beneath the root directory.
                for directory in subdirectories {
                    match directory {
                        Ok(dir) => self.index_directory_files(&dir.path(), prefix_length),
                        Err(_) => (),
                    }
                }
            },
            Err(_) => return,
        };
    }

    /// Helper method for populate.
    /// Finds files for a particular directory, strips prefix_length leading
    /// characters from their path, and adds them to the index entries vector.
    fn index_directory_files(&mut self, directory: &Path, prefix_length: usize) {
        match fs::read_dir(directory) {
            Ok(entries) => {
                // Put all of the file-based Path entries into the index.
                for entry in entries {
                    match relative_entry_path(entry, prefix_length) {
                        Some(entry_path) => self.entries.push(PathBuf::from(entry_path)),
                        _ => (),
                    }
                }
            },
            Err(_) => (),
        }
    }
}

pub fn new(path: PathBuf) -> Index {
    return Index { path: path, entries: vec![] }
}

/// Transforms a DirEntry object into an optional relative path string,
/// returning None if any errors occur or if the entry is not a file.
fn relative_entry_path(entry: Result<DirEntry, Error>, prefix_length: usize) -> Option<String> {
    match entry {
        Ok(e) => match e.path().metadata() {
            Ok(metadata) => if metadata.is_file() {
                match e.path().to_str() {
                    Some(path) => Some(path[prefix_length..].to_string()),
                    _ => None,
                }
            } else {
                None
            },
            _ => None,
        },
        _ => None,
    }
}

#[test]
fn new_creates_index_with_passed_path() {
    let path = "my path";
    let index = Index::new(path);

    // Get the index path as a string.
    let index_path = match index.path.to_str() {
        Some(value) => value,
        None => ""
    };

    assert_eq!(index_path, path);
}

#[test]
fn new_creates_index_with_empty_array() {
    let path = "my path";
    let index = Index::new(path);
    let empty_array: Vec<PathBuf> = vec![];

    assert!(index.entries == empty_array);
}

#[test]
fn populate_adds_all_files_to_entries() {
    let path = "tests/sample";
    let index = &mut Index::new(path);
    let expected_array = vec![PathBuf::from("root_file"), PathBuf::from("directory/nested_file")];
    index.populate();

    assert!(index.entries == expected_array);
}
<commit_msg>Refactor index tests.<commit_after>use std::fs;
use std::fs::{PathExt, DirEntry};
use std::path::{Path, PathBuf};
use std::io::Error;

pub struct Index {
    path: PathBuf,
    entries: Vec<PathBuf>,
}

impl Index {
    /// Finds all files inside and beneath the index path
    /// and adds them to the index entries vector.
    pub fn populate(&mut self) {
        // The entries listed by read_dir include the root index path; we want
        // relative paths, so we get this length so that we can strip it.
        let prefix_length = match self.path.to_str() {
            Some(path) => path.len()+1,
            None => return,
        };

        // Start by getting any files in the root path. Since
        // read_directory_entries is already borrowing a mutable
        // reference to the index, so we can't also lend out a
        // reference to its path field, hence the clone.
        let path = self.path.clone();
        self.index_directory_files(&path, prefix_length);

        // Get an iterator that'll let us walk all of the subdirectories
        // of the index path, bailing out if there's an error of any kind.
        match fs::walk_dir(&self.path) {
            Ok(subdirectories) => {
                // Index any other files beneath the root directory.
                for directory in subdirectories {
                    match directory {
                        Ok(dir) => self.index_directory_files(&dir.path(), prefix_length),
                        Err(_) => (),
                    }
                }
            },
            Err(_) => return,
        };
    }

    /// Helper method for populate.
    /// Finds files for a particular directory, strips prefix_length leading
    /// characters from their path, and adds them to the index entries vector.
    fn index_directory_files(&mut self, directory: &Path, prefix_length: usize) {
        match fs::read_dir(directory) {
            Ok(entries) => {
                // Put all of the file-based Path entries into the index.
                for entry in entries {
                    match relative_entry_path(entry, prefix_length) {
                        Some(entry_path) => self.entries.push(PathBuf::from(entry_path)),
                        _ => (),
                    }
                }
            },
            Err(_) => (),
        }
    }
}

pub fn new(path: PathBuf) -> Index {
    Index {
        path: path,
        entries: Vec::new(),
    }
}

/// Transforms a DirEntry object into an optional relative path string,
/// returning None if any errors occur or if the entry is not a file.
fn relative_entry_path(entry: Result<DirEntry, Error>, prefix_length: usize) -> Option<String> {
    match entry {
        Ok(e) => match e.path().metadata() {
            Ok(metadata) => if metadata.is_file() {
                match e.path().to_str() {
                    Some(path) => Some(path[prefix_length..].to_string()),
                    _ => None,
                }
            } else {
                None
            },
            _ => None,
        },
        _ => None,
    }
}

#[cfg(test)]
mod tests {
    use super::new;
    use std::path::PathBuf;

    #[test]
    fn populate_adds_all_files_to_entries() {
        let path = PathBuf::from("tests/sample");
        let mut index = new(path);
        let expected_array = vec![PathBuf::from("root_file"), PathBuf::from("directory/nested_file")];
        index.populate();

        assert!(index.entries == expected_array);
    }
}
<|endoftext|>


<commit_before>use std::string::ToString;
use std::collections::BTreeMap;
use std::error::Error;
use std::fmt;
use std::{i32,usize};
use rustc_serialize::json::{Json,ToJson};

use parse::Presence::*;

#[derive(Clone, PartialEq, Debug)]
pub enum ParseError {
    InvalidJsonType(String),
    InvalidStructure(String),
    MissingField(String),
    UnknownMethod(String),
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::InvalidJsonType(_)  => "invalid JSON type for conversion",
            ParseError::InvalidStructure(_) => "invalid value structure for conversion",
            ParseError::MissingField(_)     => "missing field",
            ParseError::UnknownMethod(_)    => "unknown method",
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            ParseError::InvalidJsonType(ref e)  => format!("invalid JSON type for conversion to {}", e),
            ParseError::InvalidStructure(ref e) => format!("invalid value structure for conversion to {}", e),
            ParseError::MissingField(ref e)     => format!("missing field \"{}\"", e),
            ParseError::UnknownMethod(ref e)    => format!("unknown method \"{}\"", e),
        }.to_string())
    }
}

#[derive(Clone, PartialEq, Debug)]
pub enum Presence<T> {
    Present(T),
    Absent,
}
impl<T> Presence<T> {
    pub fn as_option<'a>(&'a self) -> Option<&'a T> {
        match *self {
            Present(ref tt) => Some(&tt),
            Absent          => None,
        }
    }
}
impl<T> Default for Presence<T> {
    fn default() -> Presence<T> {
        Absent
    }
}

// trait for things that can be created from a JSON fragment
pub trait FromJson {
    fn from_json(json: &Json) -> Result<Self,ParseError>;
}

// conversions for system types
impl FromJson for String {
    fn from_json(json: &Json) -> Result<String,ParseError> {
        match *json {
            Json::String(ref s) => Ok(s.to_string()),
            _                   => Err(ParseError::InvalidJsonType("String".to_string())),
        }
    }
}
impl FromJson for u64 {
    fn from_json(json: &Json) -> Result<u64,ParseError> {
        match *json {
            Json::U64(n) => Ok(n),
            Json::I64(n) => Ok(n as u64),
            _            => Err(ParseError::InvalidJsonType("u64".to_string())),
        }
    }
}
impl FromJson for bool {
    fn from_json(json: &Json) -> Result<bool,ParseError> {
        match *json {
            Json::Boolean(b) => Ok(b),
            _                => Err(ParseError::InvalidJsonType("bool".to_string())),
        }
    }
}
impl FromJson for i32 {
    fn from_json(json: &Json) -> Result<i32,ParseError> {
        match *json {
            Json::U64(n) if n <= (i32::MAX as u64)
                => Ok(n as i32),
            Json::I64(n) if n >= (i32::MIN as i64) && n <= (i32::MAX as i64)
                => Ok(n as i32),
            _ => Err(ParseError::InvalidJsonType("i32".to_string())),
        }
    }
}
impl FromJson for usize {
    fn from_json(json: &Json) -> Result<usize,ParseError> {
        match *json {
            Json::U64(n) if n <= (usize::MAX as u64)
                => Ok(n as usize),
            Json::I64(n) if n >= (usize::MIN as i64) && n <= (usize::MAX as i64)
                => Ok(n as usize),
            _ => Err(ParseError::InvalidJsonType("usize".to_string())),
        }
    }
}

impl<T> FromJson for Vec<T> where T: FromJson {
    fn from_json(json: &Json) -> Result<Vec<T>,ParseError> {
        match *json {
            Json::Array(ref a) => {
                let (ok, mut err): (Vec<_>,Vec<_>)  = a.iter().map(|ref j| T::from_json(j)).partition(|ref r| match **r { Ok(_) => true, Err(_) => false });
                match err.len() {
                    0 => Ok(ok.into_iter().map(|r| r.ok().unwrap()).collect()),
                    _ => Err(err.remove(0).err().unwrap()),
                }
            }
            _ => Err(ParseError::InvalidJsonType("Vec".to_string())),
        }
    }
}

impl<T> FromJson for BTreeMap<String,T> where T: FromJson {
    fn from_json(json: &Json) -> Result<Self,ParseError> {
        match *json {
            Json::Object(ref o) => {
                let mut m = BTreeMap::<String,T>::new();
                for (k, v) in o.iter() {
                    let vv = try!(T::from_json(v));
                    m.insert(k.clone(), vv);
                }
                Ok(m)
            },
            _ => Err(ParseError::InvalidJsonType("BTreeMap".to_string()))
        }
    }
}

pub trait FromJsonField {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError>;
}

impl<T> FromJsonField for T where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(ref v) => T::from_json(&v),
            None        => Err(ParseError::MissingField(field.to_string())),
        }
    }
}
impl<T> FromJsonField for Option<T> where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(v) => {
                match *v {
                    Json::Null => Ok(None),
                    _ => match T::from_json(&v) {
                        Ok(j)  => Ok(Some(j)),
                        Err(e) => Err(e),
                    }
                }
            }
            None => Ok(None),
        }
    }
}
impl<T> FromJsonField for Presence<T> where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(ref v) => {
                match T::from_json(&v) {
                    Ok(j)  => Ok(Present(j)),
                    Err(e) => Err(e),
                }
            }
            None => Ok(Absent),
        }
    }
}
impl<T> FromJsonField for Presence<Option<T>> where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(v) => {
                match *v {
                    Json::Null => Ok(Present(None)),
                    _ => match T::from_json(&v) {
                        Ok(j)  => Ok(Present(Some(j))),
                        Err(e) => Err(e),
                    }
                }
            }
            None => Ok(Absent),
        }
    }
}

pub trait ToJsonField {
    fn to_json_field(&self, json: &mut BTreeMap<String,Json>, field: &str);
}

impl<T> ToJsonField for T where T: ToJson {
    fn to_json_field(&self, json: &mut BTreeMap<String,Json>, field: &str) {
        json.insert(field.to_string(), self.to_json());
    }
}

impl<T> ToJsonField for Presence<T> where T: ToJson {
    fn to_json_field(&self, json: &mut BTreeMap<String,Json>, field: &str) {
        if let Present(ref v) = *self {
            json.insert(field.to_string(), v.to_json());
        }
    }
}
<commit_msg>Fix null handling for Presence properties<commit_after>use std::string::ToString;
use std::collections::BTreeMap;
use std::error::Error;
use std::fmt;
use std::{i32,usize};
use rustc_serialize::json::{Json,ToJson};

use parse::Presence::*;

#[derive(Clone, PartialEq, Debug)]
pub enum ParseError {
    InvalidJsonType(String),
    InvalidStructure(String),
    MissingField(String),
    UnknownMethod(String),
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::InvalidJsonType(_)  => "invalid JSON type for conversion",
            ParseError::InvalidStructure(_) => "invalid value structure for conversion",
            ParseError::MissingField(_)     => "missing field",
            ParseError::UnknownMethod(_)    => "unknown method",
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            ParseError::InvalidJsonType(ref e)  => format!("invalid JSON type for conversion to {}", e),
            ParseError::InvalidStructure(ref e) => format!("invalid value structure for conversion to {}", e),
            ParseError::MissingField(ref e)     => format!("missing field \"{}\"", e),
            ParseError::UnknownMethod(ref e)    => format!("unknown method \"{}\"", e),
        }.to_string())
    }
}

#[derive(Clone, PartialEq, Debug)]
pub enum Presence<T> {
    Present(T),
    Absent,
}
impl<T> Presence<T> {
    pub fn as_option<'a>(&'a self) -> Option<&'a T> {
        match *self {
            Present(ref tt) => Some(&tt),
            Absent          => None,
        }
    }
}
impl<T> Default for Presence<T> {
    fn default() -> Presence<T> {
        Absent
    }
}

// trait for things that can be created from a JSON fragment
pub trait FromJson {
    fn from_json(json: &Json) -> Result<Self,ParseError>;
}

// conversions for system types
impl FromJson for String {
    fn from_json(json: &Json) -> Result<String,ParseError> {
        match *json {
            Json::String(ref s) => Ok(s.to_string()),
            _                   => Err(ParseError::InvalidJsonType("String".to_string())),
        }
    }
}
impl FromJson for u64 {
    fn from_json(json: &Json) -> Result<u64,ParseError> {
        match *json {
            Json::U64(n) => Ok(n),
            Json::I64(n) => Ok(n as u64),
            _            => Err(ParseError::InvalidJsonType("u64".to_string())),
        }
    }
}
impl FromJson for bool {
    fn from_json(json: &Json) -> Result<bool,ParseError> {
        match *json {
            Json::Boolean(b) => Ok(b),
            _                => Err(ParseError::InvalidJsonType("bool".to_string())),
        }
    }
}
impl FromJson for i32 {
    fn from_json(json: &Json) -> Result<i32,ParseError> {
        match *json {
            Json::U64(n) if n <= (i32::MAX as u64)
                => Ok(n as i32),
            Json::I64(n) if n >= (i32::MIN as i64) && n <= (i32::MAX as i64)
                => Ok(n as i32),
            _ => Err(ParseError::InvalidJsonType("i32".to_string())),
        }
    }
}
impl FromJson for usize {
    fn from_json(json: &Json) -> Result<usize,ParseError> {
        match *json {
            Json::U64(n) if n <= (usize::MAX as u64)
                => Ok(n as usize),
            Json::I64(n) if n >= (usize::MIN as i64) && n <= (usize::MAX as i64)
                => Ok(n as usize),
            _ => Err(ParseError::InvalidJsonType("usize".to_string())),
        }
    }
}

impl<T> FromJson for Vec<T> where T: FromJson {
    fn from_json(json: &Json) -> Result<Vec<T>,ParseError> {
        match *json {
            Json::Array(ref a) => {
                let (ok, mut err): (Vec<_>,Vec<_>)  = a.iter().map(|ref j| T::from_json(j)).partition(|ref r| match **r { Ok(_) => true, Err(_) => false });
                match err.len() {
                    0 => Ok(ok.into_iter().map(|r| r.ok().unwrap()).collect()),
                    _ => Err(err.remove(0).err().unwrap()),
                }
            }
            _ => Err(ParseError::InvalidJsonType("Vec".to_string())),
        }
    }
}

impl<T> FromJson for BTreeMap<String,T> where T: FromJson {
    fn from_json(json: &Json) -> Result<Self,ParseError> {
        match *json {
            Json::Object(ref o) => {
                let mut m = BTreeMap::<String,T>::new();
                for (k, v) in o.iter() {
                    let vv = try!(T::from_json(v));
                    m.insert(k.clone(), vv);
                }
                Ok(m)
            },
            _ => Err(ParseError::InvalidJsonType("BTreeMap".to_string()))
        }
    }
}

pub trait FromJsonField {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError>;
}

impl<T> FromJsonField for T where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(ref v) => T::from_json(&v),
            None        => Err(ParseError::MissingField(field.to_string())),
        }
    }
}
impl<T> FromJsonField for Option<T> where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(v) => {
                match *v {
                    Json::Null => Ok(None),
                    _ => match T::from_json(&v) {
                        Ok(j)  => Ok(Some(j)),
                        Err(e) => Err(e),
                    }
                }
            }
            None => Ok(None),
        }
    }
}
impl<T> FromJsonField for Presence<T> where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(ref v) => {
                match *v {
                    &Json::Null => Ok(Absent),
                    _ => match T::from_json(&v) {
                        Ok(j)  => Ok(Present(j)),
                        Err(e) => Err(e),
                    }
                }
            }
            None => Ok(Absent),
        }
    }
}
impl<T> FromJsonField for Presence<Option<T>> where T: FromJson {
    fn from_json_field(json: &BTreeMap<String,Json>, field: &str) -> Result<Self,ParseError> {
        match json.get(field) {
            Some(v) => {
                match *v {
                    Json::Null => Ok(Present(None)),
                    _ => match T::from_json(&v) {
                        Ok(j)  => Ok(Present(Some(j))),
                        Err(e) => Err(e),
                    }
                }
            }
            None => Ok(Absent),
        }
    }
}

pub trait ToJsonField {
    fn to_json_field(&self, json: &mut BTreeMap<String,Json>, field: &str);
}

impl<T> ToJsonField for T where T: ToJson {
    fn to_json_field(&self, json: &mut BTreeMap<String,Json>, field: &str) {
        json.insert(field.to_string(), self.to_json());
    }
}

impl<T> ToJsonField for Presence<T> where T: ToJson {
    fn to_json_field(&self, json: &mut BTreeMap<String,Json>, field: &str) {
        if let Present(ref v) = *self {
            json.insert(field.to_string(), v.to_json());
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::iter::Peekable;
use std::str::Chars;
use spec::Type;
use spec::Token;

pub struct Symbol {
  token: Token,
  category: Type,
  line: u32
}

pub struct Scanner {
  deque_token: VecDeque<Symbol>,
}

impl Scanner {
  pub fn new() -> Scanner {
    Scanner { deque_token: VecDeque::new() }
  }
  pub fn build_token(&mut self, p: &str) {
    let mut reader = BufReader::new(File::open(p).expect("Open failed!"));
    let mut count = 1;

    for line in reader.lines() {
      let mut iter = line.as_ref().unwrap().chars().peekable();

      loop {
        if let Some(c) = iter.next() {
          if c == ' ' { continue; }
          let (token, category) = match c {
            '+' | '-' | '/' | '*' | '=' | '<' | '>' => self.operators(c, &mut iter),
            ';' | '.' | ':' | '(' | ')' | ',' => self.delimiters(c, &mut iter),
            _ => self.literal(c, &mut iter)
          };
          self.deque_token.push_back(Symbol{ token: token, category: category, line: count });
        } else {
          break;
        }
      }
      count += 1;
    }
  }

  fn operators(&self, c: char, iter:&mut Peekable<Chars>) -> (Token, Type) {
    match c {
      '+' => (Token::Add, Type::AddOperator),
      '-' => (Token::Sub, Type::AddOperator),
      '/' => (Token::Div, Type::MulOperator),
      '*' => (Token::Mult, Type::MulOperator),
      '=' => (Token::Equal, Type::RelOperator),
      '<' => {
        if iter.peek() == Some(&'=') {
          iter.next();
          (Token::LessThanOrEqual, Type::RelOperator)
        } else if iter.peek() == Some(&'>') {
          iter.next();
          (Token::NotEqual, Type::RelOperator)
        } else {
          (Token::LessThan, Type::RelOperator)
        }
      },
      '>' => {
        if iter.peek() == Some(&'=') {
          iter.next();
          (Token::GreaterThanOrEqual, Type::RelOperator)
        } else {
          (Token::GreaterThan, Type::RelOperator)
        }
      }
      _ => unimplemented!()
    }
  }

  fn delimiters(&self, c: char, iter: &mut Peekable<Chars>) -> (Token, Type) {
    match c {
      ';' => (Token::Semicolon, Type::Delimiter),
      '.' => (Token::Colon, Type::Delimiter),
      '(' => (Token::LParentheses, Type::Delimiter),
      ')' => (Token::RParentheses, Type::Delimiter),
      ',' => (Token::Comma, Type::Delimiter),
      ':' => {
        if iter.peek() == Some(&'=') {
          iter.next();
          (Token::Assign, Type::Command)
        } else {
          (Token::Period, Type::Delimiter)
        }
      },
      _ => unimplemented!()
    }
  }

  fn literal(&self, c: char, iter: &mut Peekable<Chars>) -> (Token, Type) {
    if c.is_digit(10) {
      self.literal_num(c, iter)
    } else if c.is_alphabetic() {
      self.literal_str(c, iter)
    } else {
      panic!("Unexpected Symbol!")
    }
  }

  fn literal_num(&self, c: char, iter: &mut Peekable<Chars>) -> (Token, Type) {
    let mut num = c.to_string();

    while self.is_digit(iter) {
      num.push(iter.next().unwrap());
    }

    if iter.peek() == Some(&'.') {
      num.push(iter.next().unwrap());

      while self.is_digit(iter) {
        num.push(iter.next().unwrap());
      }
      (Token::LitReal(num.parse().unwrap()), Type::RealLiteral)
    } else {
      (Token::LitInt(num.parse().unwrap()), Type::IntLiteral)
    }
  }

  fn literal_str(&self, c: char, iter: &mut Peekable<Chars>) -> (Token, Type) {
    let mut word = c.to_string();

    while self.is_alphanumeric_or_underl(iter) {
      word.push(iter.next().unwrap());
    }
    match &*word {
      "program" => (Token::Program, Type::Keyword),
      "var"  => (Token::Var, Type::Keyword),
      "integer" => (Token::Integer, Type::Keyword),
      "real" => (Token::Real, Type::Keyword),
      "boolean" => (Token::Boolean, Type::Keyword),
      "procedure" => (Token::Procedure, Type::Keyword),
      "begin" => (Token::Begin, Type::Keyword),
      "end" => (Token::End, Type::Keyword),
      "if" => (Token::If, Type::Keyword),
      "then" => (Token::Then, Type::Keyword),
      "else" => (Token::Else, Type::Keyword),
      "while" => (Token::While, Type::Keyword),
      "do" => (Token::Do, Type::Keyword),
      "not" => (Token::Not, Type::Keyword),
      "or" => (Token::Or, Type::AddOperator),
      "and" => (Token::And, Type::MulOperator),
      _ => (Token::LitStr(word), Type::Identifier)
    }
  }

  pub fn next_symbol(&mut self) -> Symbol {
    self.deque_token.pop_front().expect("Deque token is empty!")
  }

  fn is_digit(&self, iter:&mut Peekable<Chars>) -> bool {
    match iter.peek() {
      Some(c) => c.is_digit(10),
      _ => false
    }
  }

  fn is_alphanumeric_or_underl(&self, iter: &mut Peekable<Chars>) -> bool {
    match iter.peek() {
      Some(c) => if c.is_alphanumeric() || c==&'_' { true } else { false },
      _ => false
    }
  }
}

#[test]
fn test_token_operator() {
  let mut s: Scanner = Scanner::new();
  s.build_token("files/program1.txt");

  assert_eq!(s.next_symbol().token, Token::Add);
  assert_eq!(s.next_symbol().token, Token::Sub);
  assert_eq!(s.next_symbol().token, Token::Mult);
  assert_eq!(s.next_symbol().token, Token::Div);
  assert_eq!(s.next_symbol().token, Token::Equal);
  assert_eq!(s.next_symbol().token, Token::LessThan);
  assert_eq!(s.next_symbol().token, Token::GreaterThan);
  assert_eq!(s.next_symbol().token, Token::LessThanOrEqual);
  assert_eq!(s.next_symbol().token, Token::GreaterThanOrEqual);
  assert_eq!(s.next_symbol().token, Token::NotEqual);
  assert_eq!(s.next_symbol().token, Token::And);
  assert_eq!(s.next_symbol().token, Token::Or);
}

#[test]
fn test_token_delimiter() {
  let mut s: Scanner = Scanner::new();
  s.build_token("files/program2.txt");

  assert_eq!(s.next_symbol().token, Token::Semicolon);
  assert_eq!(s.next_symbol().token, Token::Colon);
  assert_eq!(s.next_symbol().token, Token::Period);
  assert_eq!(s.next_symbol().token, Token::LParentheses);
  assert_eq!(s.next_symbol().token, Token::RParentheses);
  assert_eq!(s.next_symbol().token, Token::Comma);
  assert_eq!(s.next_symbol().token, Token::Assign);
}

#[test]
fn test_token_literal_num() {
  let mut s: Scanner = Scanner::new();
  s.build_token("files/program3.txt");

  assert_eq!(s.next_symbol().token, Token::LitInt(22));
  assert_eq!(s.next_symbol().token, Token::LitInt(19));
  assert_eq!(s.next_symbol().token, Token::LitReal(11.2));
  assert_eq!(s.next_symbol().token, Token::LitReal(932.2));
  assert_eq!(s.next_symbol().token, Token::LitInt(1));
  assert_eq!(s.next_symbol().token, Token::LitReal(1.0));
}

#[test]
fn test_token_keywords() {
  let mut s: Scanner = Scanner::new();
  s.build_token("files/program4.txt");

  assert_eq!(s.next_symbol().token, Token::Var);
  assert_eq!(s.next_symbol().token, Token::End);
  assert_eq!(s.next_symbol().token, Token::If);
  assert_eq!(s.next_symbol().token, Token::Then);
  assert_eq!(s.next_symbol().token, Token::Integer);
  assert_eq!(s.next_symbol().token, Token::Real);
  assert_eq!(s.next_symbol().token, Token::Boolean);
  assert_eq!(s.next_symbol().token, Token::Procedure);
  assert_eq!(s.next_symbol().token, Token::Begin);
  assert_eq!(s.next_symbol().token, Token::Else);
  assert_eq!(s.next_symbol().token, Token::While);
  assert_eq!(s.next_symbol().token, Token::Do);
  assert_eq!(s.next_symbol().token, Token::Not);
  assert_eq!(s.next_symbol().token, Token::Program);
}
<commit_msg>Adiciona tratamento de espaços em brancos e comentário<commit_after>use std::collections::VecDeque;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::iter::Peekable;
use std::str::Chars;
use spec::Type;
use spec::Token;

pub struct Symbol {
  token: Token,
  category: Type,
  line: u32
}

pub struct Scanner {
  deque_token: VecDeque<Symbol>,
}

impl Scanner {
  pub fn new() -> Scanner {
    Scanner { deque_token: VecDeque::new() }
  }
  pub fn build_token(&mut self, p: &str) {
    let mut reader = BufReader::new(File::open(p).expect("Open failed!"));
    let mut count = 1;
    let mut block_comment = false;

    for line in reader.lines() {
      let mut iter = line.as_ref().unwrap().chars().peekable();

      loop {
        if let Some(c) = iter.next() {
          if c == ' ' {
            while iter.peek() == Some(&' ') { iter.next(); }
          } else if c == '{' || block_comment {
            while iter.peek() != Some(&'}') { iter.next(); }
            if iter.next() == Some('}') {
              block_comment = false;
            } else {
              block_comment = true;
            }
          } else {
            let (token, category) = match c {
              '+' | '-' | '/' | '*' | '=' | '<' | '>' => self.operators(c, &mut iter),
              ';' | '.' | ':' | '(' | ')' | ',' => self.delimiters(c, &mut iter),
              _ => self.literal(c, &mut iter)
            };
            self.deque_token.push_back(Symbol{ token: token, category: category, line: count });
          }
        } else {
          break;
        }
      }
      if block_comment { panic!("Error: Unterminated comment"); }
      count += 1;
    }
  }

  fn operators(&self, c: char, iter:&mut Peekable<Chars>) -> (Token, Type) {
    match c {
      '+' => (Token::Add, Type::AddOperator),
      '-' => (Token::Sub, Type::AddOperator),
      '/' => (Token::Div, Type::MulOperator),
      '*' => (Token::Mult, Type::MulOperator),
      '=' => (Token::Equal, Type::RelOperator),
      '<' => {
        if iter.peek() == Some(&'=') {
          iter.next();
          (Token::LessThanOrEqual, Type::RelOperator)
        } else if iter.peek() == Some(&'>') {
          iter.next();
          (Token::NotEqual, Type::RelOperator)
        } else {
          (Token::LessThan, Type::RelOperator)
        }
      },
      '>' => {
        if iter.peek() == Some(&'=') {
          iter.next();
          (Token::GreaterThanOrEqual, Type::RelOperator)
        } else {
          (Token::GreaterThan, Type::RelOperator)
        }
      }
      _ => unimplemented!()
    }
  }

  fn delimiters(&self, c: char, iter: &mut Peekable<Chars>) -> (Token, Type) {
    match c {
      ';' => (Token::Semicolon, Type::Delimiter),
      '.' => (Token::Colon, Type::Delimiter),
      '(' => (Token::LParentheses, Type::Delimiter),
      ')' => (Token::RParentheses, Type::Delimiter),
      ',' => (Token::Comma, Type::Delimiter),
      ':' => {
        if iter.peek() == Some(&'=') {
          iter.next();
          (Token::Assign, Type::Command)
        } else {
          (Token::Period, Type::Delimiter)
        }
      },
      _ => unimplemented!()
    }
  }

  fn literal(&self, c: char, iter: &mut Peekable<Chars>) -> (Token, Type) {
    if c.is_digit(10) {
      self.literal_num(c, iter)
    } else if c.is_alphabetic() {
      self.literal_str(c, iter)
    } else {
      panic!("Error: Unexpected Symbol!")
    }
  }

  fn literal_num(&self, c: char, iter: &mut Peekable<Chars>) -> (Token, Type) {
    let mut num = c.to_string();

    while self.is_digit(iter) {
      num.push(iter.next().unwrap());
    }

    if iter.peek() == Some(&'.') {
      num.push(iter.next().unwrap());

      while self.is_digit(iter) {
        num.push(iter.next().unwrap());
      }
      (Token::LitReal(num.parse().unwrap()), Type::RealLiteral)
    } else {
      (Token::LitInt(num.parse().unwrap()), Type::IntLiteral)
    }
  }

  fn literal_str(&self, c: char, iter: &mut Peekable<Chars>) -> (Token, Type) {
    let mut word = c.to_string();

    while self.is_alphanumeric_or_underl(iter) {
      word.push(iter.next().unwrap());
    }
    match &*word {
      "program" => (Token::Program, Type::Keyword),
      "var"  => (Token::Var, Type::Keyword),
      "integer" => (Token::Integer, Type::Keyword),
      "real" => (Token::Real, Type::Keyword),
      "boolean" => (Token::Boolean, Type::Keyword),
      "procedure" => (Token::Procedure, Type::Keyword),
      "begin" => (Token::Begin, Type::Keyword),
      "end" => (Token::End, Type::Keyword),
      "if" => (Token::If, Type::Keyword),
      "then" => (Token::Then, Type::Keyword),
      "else" => (Token::Else, Type::Keyword),
      "while" => (Token::While, Type::Keyword),
      "do" => (Token::Do, Type::Keyword),
      "not" => (Token::Not, Type::Keyword),
      "or" => (Token::Or, Type::AddOperator),
      "and" => (Token::And, Type::MulOperator),
      _ => (Token::LitStr(word), Type::Identifier)
    }
  }

  pub fn next_symbol(&mut self) -> Symbol {
    self.deque_token.pop_front().expect("Error: Deque token is empty!")
  }

  fn is_digit(&self, iter:&mut Peekable<Chars>) -> bool {
    match iter.peek() {
      Some(c) => c.is_digit(10),
      _ => false
    }
  }

  fn is_alphanumeric_or_underl(&self, iter: &mut Peekable<Chars>) -> bool {
    match iter.peek() {
      Some(c) => if c.is_alphanumeric() || c==&'_' { true } else { false },
      _ => false
    }
  }
}

#[test]
fn test_token_operator() {
  let mut s: Scanner = Scanner::new();
  s.build_token("files/program1.txt");

  assert_eq!(s.next_symbol().token, Token::Add);
  assert_eq!(s.next_symbol().token, Token::Sub);
  assert_eq!(s.next_symbol().token, Token::Mult);
  assert_eq!(s.next_symbol().token, Token::Div);
  assert_eq!(s.next_symbol().token, Token::Equal);
  assert_eq!(s.next_symbol().token, Token::LessThan);
  assert_eq!(s.next_symbol().token, Token::GreaterThan);
  assert_eq!(s.next_symbol().token, Token::LessThanOrEqual);
  assert_eq!(s.next_symbol().token, Token::GreaterThanOrEqual);
  assert_eq!(s.next_symbol().token, Token::NotEqual);
  assert_eq!(s.next_symbol().token, Token::And);
  assert_eq!(s.next_symbol().token, Token::Or);
}

#[test]
fn test_token_delimiter() {
  let mut s: Scanner = Scanner::new();
  s.build_token("files/program2.txt");

  assert_eq!(s.next_symbol().token, Token::Semicolon);
  assert_eq!(s.next_symbol().token, Token::Colon);
  assert_eq!(s.next_symbol().token, Token::Period);
  assert_eq!(s.next_symbol().token, Token::LParentheses);
  assert_eq!(s.next_symbol().token, Token::RParentheses);
  assert_eq!(s.next_symbol().token, Token::Comma);
  assert_eq!(s.next_symbol().token, Token::Assign);
}

#[test]
fn test_token_literal_num() {
  let mut s: Scanner = Scanner::new();
  s.build_token("files/program3.txt");

  assert_eq!(s.next_symbol().token, Token::LitInt(22));
  assert_eq!(s.next_symbol().token, Token::LitInt(19));
  assert_eq!(s.next_symbol().token, Token::LitReal(11.2));
  assert_eq!(s.next_symbol().token, Token::LitReal(932.2));
  assert_eq!(s.next_symbol().token, Token::LitInt(1));
  assert_eq!(s.next_symbol().token, Token::LitReal(1.0));
}

#[test]
fn test_token_keywords() {
  let mut s: Scanner = Scanner::new();
  s.build_token("files/program4.txt");

  assert_eq!(s.next_symbol().token, Token::Var);
  assert_eq!(s.next_symbol().token, Token::End);
  assert_eq!(s.next_symbol().token, Token::If);
  assert_eq!(s.next_symbol().token, Token::Then);
  assert_eq!(s.next_symbol().token, Token::Integer);
  assert_eq!(s.next_symbol().token, Token::Real);
  assert_eq!(s.next_symbol().token, Token::Boolean);
  assert_eq!(s.next_symbol().token, Token::Procedure);
  assert_eq!(s.next_symbol().token, Token::Begin);
  assert_eq!(s.next_symbol().token, Token::Else);
  assert_eq!(s.next_symbol().token, Token::While);
  assert_eq!(s.next_symbol().token, Token::Do);
  assert_eq!(s.next_symbol().token, Token::Not);
  assert_eq!(s.next_symbol().token, Token::Program);
}
<|endoftext|>


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

#[derive(Debug, PartialEq)]
pub enum Token {
	Identifier(String),
	Value(i32),
	Register(usize),

}

pub fn tokenize(input: &str) -> Vec<Token> {
	let mut tokens: Vec<Token> = Vec::new();
	let mut tokenizer = Lexer::new(input);

	tokens
}

pub struct Lexer<'a> {
	input: &'a str,
	iter: Peekable<CharIndices<'a>>,
	pos: usize,
	line: u32,
	column: u32,
}

impl<'a> Lexer<'a> {
	fn new(input : &str) -> Lexer {
		Lexer {
			input: input,
			iter: input.char_indices().peekable(),
			pos: 0,
			line: 1,
			column: 1
		}
	}
	fn advance(&mut self) -> Option<char> {
		if let Some((i, c)) = self.iter.next() {

			match c  {
				'\n' => {
					self.column = 1;
					self.line  += 1;
				}
				'\t' => {
					self.column  += 4;

				}
				_ => self.column += 1

			}
			self.pos = i;
			return Some(c);
		}
		None
	}
	fn advance_while<P: Fn(char) -> bool>(&mut self, p: P) {
		loop {
			match self.peek() {
				Some(c) => {
					match p(c) {
						false => break,
						true => continue
					}
				}
				None => break
			}
			self.advance();
		}
	}
	fn peek(&mut self) -> Option<char> {
		if let Some(&(_, c)) = self.iter.peek() {
			return Some(c);
		}
		None
	}
	fn handle_alphabetic(&mut self) -> Token {
		//todo
		unimplemented!()
	}
	fn handle_number(&mut self) -> Token {
		let start = self.pos;
		self.advance_while(is_numeric);
		Token::Value(self.input[start..self.pos].parse().unwrap())
	}
	fn handle_other(&mut self) -> Token {
		//todo
		unimplemented!()
	}
}

impl<'a> Iterator for Lexer<'a> {
	type Item = Token;
	fn next(&mut self) -> Option<Token> {
		let token = match self.peek() {
			Some(c) if is_alphabetic(c) => self.handle_alphabetic(),
			Some(c) if is_numeric(c) => self.handle_number(),
			Some(c) if !is_numeric(c) && !is_alphabetic(c) => self.handle_other(),
			_ =>  unreachable!()
		};
		Some(token)

	}
}

fn is_numeric(c: char) -> bool {
	match c {
		'0'...'9' => true,
		_ => false
	}
}
fn is_alphabetic(c: char) -> bool {
	match c {
		'a' ... 'z' | 'A' ... 'Z' => true,
		_ => false
	}
}<commit_msg>handle numbers<commit_after>use std::str::CharIndices;
use std::iter::Peekable;

#[derive(Debug, PartialEq)]
pub enum Token {
	Identifier(String),
	Value(i32),
	Register(usize),

}

pub fn tokenize(input: &str) -> Vec<Token> {
	let mut tokens: Vec<Token> = Vec::new();
	let mut tokenizer = Lexer::new(input);

	loop {
		match tokenizer.next() {
			Some(t) => {

				tokens.push(t);

			},
			None => break
		}
	}
	tokens
}

pub struct Lexer<'a> {
	input: &'a str,
	iter: Peekable<CharIndices<'a>>,
	pos: usize,
	line: u32,
	column: u32,
}

impl<'a> Lexer<'a> {
	fn new(input : &str) -> Lexer {
		Lexer {
			input: input,
			iter: input.char_indices().peekable(),
			pos: 0,
			line: 1,
			column: 1
		}
	}
	fn advance(&mut self) -> Option<char> {

		if let Some((i, c)) = self.iter.next() {
			match c  {
				'\n' => {
					self.column = 1;
					self.line  += 1;
				},

				'\t' => {
					self.column  += 4;

				},
				_ => self.column += 1

			}
			self.pos = i;
			return Some(c);
		}
		None
	}
	fn advance_while<P: Fn(char) -> bool>(&mut self, p: P) {
		loop {

			match self.peek() {
				Some(c) => {

					match p(c) {
						false => break,
						true => continue
					}
				}
				None => break
			}
			self.advance();
		}
	}
	fn peek(&mut self) -> Option<char> {
		if let Some(&(_, c)) = self.iter.peek() {
			return Some(c);
		}
		None
	}
	fn handle_alphabetic(&mut self) -> Token {
		//todo
		unimplemented!()
	}
	fn handle_number(&mut self) -> Token {
		let start = self.pos;
		self.advance_while(is_numeric);

		Token::Value(self.input[start..self.pos].parse().unwrap())

	}
	fn handle_other(&mut self) -> Token {
		//todo
		unimplemented!()
	}
}

impl<'a> Iterator for Lexer<'a> {
	type Item = Token;
	fn next(&mut self) -> Option<Token> {
		let token = match self.peek() {
			Some(c) if is_alphabetic(c) => self.handle_alphabetic(),
			Some(c) if is_numeric(c) => self.handle_number(),
			Some(c) if !is_numeric(c) && !is_alphabetic(c) => self.handle_other(),
			_ =>  unreachable!()
		};
		Some(token)

	}
}

fn is_numeric(c: char) -> bool {
	match c {
		'0'...'9' => true,
		_ => false
	}
}
fn is_alphabetic(c: char) -> bool {
	match c {
		'a' ... 'z' | 'A' ... 'Z' => true,
		_ => false
	}
}
<|endoftext|>


<commit_before>use std;

#[derive(Debug,Clone,PartialEq)]
pub enum Token {
  // Structure
  EOF,
  Enter,
  Exit,
  Space,
  Comment(String),

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  StrLit(String),
  Name(String),

  // Keywords
  Break,
  Continue,
  Else,
  For,
  Func,
  If,
  In,
  Return,
  While,

  // Symbols
  Arr, // ->
  Ass, // =
  Col, // :
  Com, // ,
  Dot, // .
  Meta,// ::
  Semi,// ;

  // Braces
  Cul, // {
  Cur, // }
  Pal, // (
  Par, // )
  Sql, // [
  Sqr, // ]

  // Operators
  Add, // +
  And, // &
  Car, // ^
  Div, // /
  Dol, // $
  Mul, // *
  Neg, // ~
  Not, // !
  Or,  // |
  Pct, // %
  Sub, // -

  // Comparisons
  Eql, // ==
  Ge,  // >=
  Gt,  // >
  Le,  // <=
  Lt,  // <
  Ne,  // !=
}

use self::Token::*;

fn lex_number(it: &mut std::iter::Peekable<std::str::Chars>) -> Token {
  let mut digits = String::new();
  while let Some(&c) = it.peek() {
    match c {
      '0'...'9' | '.' => {
        it.next();
        digits.push(c);
      }
      _ => {break}
    }
  }

  match digits.contains(".") {
    true => Float(digits.parse::<f64>().unwrap()),
    false => Int(digits.parse::<i64>().unwrap())
  }
}

fn lex_name(it: &mut std::iter::Peekable<std::str::Chars>) -> Token {
  let mut name = String::new();
  name.push(it.next().unwrap());

  while let Some(&c) = it.peek() {
    match c {
      'a'...'z' | 'A'...'Z' | '0'...'9' | '_' => {
        it.next();
        name.push(c);
      }
      _ => {break}
    }
  }

  match name.as_str() {
    "true" => Bool(true),
    "false" => Bool(false),
    "break" => Break,
    "continue" => Continue,
    "else" => Else,
    "for" => For,
    "func" => Func,
    "if" => If,
    "in" => In,
    "return" => Return,
    "while" => While,
    _ => Name(name)
  }
}

fn lex_pair(next: char, solo: Token, pair: Token, it: &mut std::iter::Peekable<std::str::Chars>) -> Token {
  it.next();

  if let Some(&c) = it.peek() {
    if c == next {
      it.next();
      return pair;
    }
  }

  // is this right? if peek() returns a None, we just return `solo`?
  // seems right. None should be the EOF, meaning `solo` is the last token
  solo
}

pub fn lex(input: &str) -> Vec<Token> {
  let mut tokens: Vec<Token> = Vec::new();
  let mut it = input.chars().peekable();

  while let Some(&c) = it.peek() {
    let x = match c {
      'a'...'z' | 'A'...'Z' | '_' => lex_name(&mut it),
      '0'...'9' => lex_number(&mut it),

      // Compound
      '-' => lex_pair('>', Sub, Arr, &mut it),
      '<' => lex_pair('=', Lt, Le, &mut it),
      '>' => lex_pair('=', Gt, Ge, &mut it),
      '=' => lex_pair('=', Ass, Eql, &mut it),
      '!' => lex_pair('=', Not, Ne, &mut it),
      ':' => lex_pair(':', Col, Meta, &mut it),

      // Symbols
      // -> Arr
      // = Ass
      // : Col
      ',' => {it.next(); Com}
      '.' => {it.next(); Dot}
      // :: Meta
      ';' => {it.next(); Semi}

      // Braces
      '(' => {it.next(); Pal}
      ')' => {it.next(); Par}
      '[' => {it.next(); Sql}
      ']' => {it.next(); Sqr}
      '{' => {it.next(); Cul}
      '}' => {it.next(); Cur}

      // Operators
      '+' => {it.next(); Add}
      '&' => {it.next(); And}
      '^' => {it.next(); Car}
      '/' => {it.next(); Div}
      '$' => {it.next(); Dol}
      '*' => {it.next(); Mul}
      '~' => {it.next(); Neg}
      // ! Not
      '|' => {it.next(); Or}
      '%' => {it.next(); Pct}
      // - Sub

      _ => {it.next(); Space}
    };

    // don't emit tokens for spaces or comments
    match x {
     Space => (),
     Comment(_) => (),
      _ => tokens.push(x),
    }

  }

  tokens
}
<commit_msg>lexer: Add comment lexing<commit_after>use std;

#[derive(Debug,Clone,PartialEq)]
pub enum Token {
  // Structure
  EOF,
  Enter,
  Exit,
  Space,
  Comment(String),

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  StrLit(String),
  Name(String),

  // Keywords
  Break,
  Continue,
  Else,
  For,
  Func,
  If,
  In,
  Return,
  While,

  // Symbols
  Arr, // ->
  Ass, // =
  Col, // :
  Com, // ,
  Dot, // .
  Meta,// ::
  Semi,// ;

  // Braces
  Cul, // {
  Cur, // }
  Pal, // (
  Par, // )
  Sql, // [
  Sqr, // ]

  // Operators
  Add, // +
  And, // &
  Car, // ^
  Div, // /
  Dol, // $
  Mul, // *
  Neg, // ~
  Not, // !
  Or,  // |
  Pct, // %
  Sub, // -

  // Comparisons
  Eql, // ==
  Ge,  // >=
  Gt,  // >
  Le,  // <=
  Lt,  // <
  Ne,  // !=
}

use self::Token::*;

fn lex_number(it: &mut std::iter::Peekable<std::str::Chars>) -> Token {
  let mut digits = String::new();
  while let Some(&c) = it.peek() {
    match c {
      '0'...'9' | '.' => {
        it.next();
        digits.push(c);
      }
      _ => {break}
    }
  }

  match digits.contains(".") {
    true => Float(digits.parse::<f64>().unwrap()),
    false => Int(digits.parse::<i64>().unwrap())
  }
}

fn lex_name(it: &mut std::iter::Peekable<std::str::Chars>) -> Token {
  let mut name = String::new();
  name.push(it.next().unwrap());

  while let Some(&c) = it.peek() {
    match c {
      'a'...'z' | 'A'...'Z' | '0'...'9' | '_' => {
        it.next();
        name.push(c);
      }
      _ => {break}
    }
  }

  match name.as_str() {
    "true" => Bool(true),
    "false" => Bool(false),
    "break" => Break,
    "continue" => Continue,
    "else" => Else,
    "for" => For,
    "func" => Func,
    "if" => If,
    "in" => In,
    "return" => Return,
    "while" => While,
    _ => Name(name)
  }
}

fn lex_comment(it: &mut std::iter::Peekable<std::str::Chars>) -> Token {
  let mut comment = String::new();
  it.next();

  while let Some(&c) = it.peek() {
    match c {
      '\n' => {break}
      _ => {
        it.next();
        comment.push(c);
      }
    }
  }

  println!("Comment: {:?}", comment);
  Comment(comment)
}

fn lex_pair(next: char, solo: Token, pair: Token, it: &mut std::iter::Peekable<std::str::Chars>) -> Token {
  it.next();

  if let Some(&c) = it.peek() {
    if c == next {
      it.next();
      return pair;
    }
  }

  // is this right? if peek() returns a None, we just return `solo`?
  // seems right. None should be the EOF, meaning `solo` is the last token
  solo
}

pub fn lex(input: &str) -> Vec<Token> {
  let mut tokens: Vec<Token> = Vec::new();
  let mut it = input.chars().peekable();

  while let Some(&c) = it.peek() {
    let x = match c {
      '#' => lex_comment(&mut it),
      'a'...'z' | 'A'...'Z' | '_' => lex_name(&mut it),
      '0'...'9' => lex_number(&mut it),

      // Compound
      '-' => lex_pair('>', Sub, Arr, &mut it),
      '<' => lex_pair('=', Lt, Le, &mut it),
      '>' => lex_pair('=', Gt, Ge, &mut it),
      '=' => lex_pair('=', Ass, Eql, &mut it),
      '!' => lex_pair('=', Not, Ne, &mut it),
      ':' => lex_pair(':', Col, Meta, &mut it),

      // Symbols
      // -> Arr
      // = Ass
      // : Col
      ',' => {it.next(); Com}
      '.' => {it.next(); Dot}
      // :: Meta
      ';' => {it.next(); Semi}

      // Braces
      '(' => {it.next(); Pal}
      ')' => {it.next(); Par}
      '[' => {it.next(); Sql}
      ']' => {it.next(); Sqr}
      '{' => {it.next(); Cul}
      '}' => {it.next(); Cur}

      // Operators
      '+' => {it.next(); Add}
      '&' => {it.next(); And}
      '^' => {it.next(); Car}
      '/' => {it.next(); Div}
      '$' => {it.next(); Dol}
      '*' => {it.next(); Mul}
      '~' => {it.next(); Neg}
      // ! Not
      '|' => {it.next(); Or}
      '%' => {it.next(); Pct}
      // - Sub

      _ => {it.next(); Space}
    };

    // don't emit tokens for spaces or comments
    match x {
     Space => (),
     Comment(_) => (),
      _ => tokens.push(x),
    }

  }

  tokens
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
// Copyright (c) font-loader Developers
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/// Font loading utilities for installed system fonts
pub mod system_fonts {
    use core_text::font_descriptor::*;
    use core_text::font_descriptor;
    use core_text;
    use std::fs::File;
    use std::mem;
    use std::ptr;
    use core_foundation::string::CFString;
    use core_foundation::number::CFNumber;
    use core_foundation::array::CFArray;
    use core_foundation::dictionary::CFDictionary;
    use core_foundation::base::{CFType, TCFType};
    use core_foundation::url::CFURL;
    use libc::c_int;
    use std::io::Read;
    /// The platform specific font properties
    pub type FontProperty = CTFontDescriptor;

    /// Builder for FontProperty
    pub struct FontPropertyBuilder {
        symbolic_traits: CTFontSymbolicTraits,
        family: String
    }

    impl FontPropertyBuilder {
        pub fn new() -> FontPropertyBuilder {
            FontPropertyBuilder{ symbolic_traits: 0, family: String::new()}
        }

        pub fn italic(mut self) -> FontPropertyBuilder {
            self.symbolic_traits |= kCTFontItalicTrait;
            self
        }

        pub fn oblique(self) -> FontPropertyBuilder {
            self.italic()
        }

        pub fn monospace(mut self) -> FontPropertyBuilder {
            self.symbolic_traits |= kCTFontMonoSpaceTrait;
            self
        }

        pub fn bold(mut self) -> FontPropertyBuilder {
            self.symbolic_traits |= kCTFontBoldTrait;
            self
        }

        pub fn family(mut self, name: &str) -> FontPropertyBuilder {
            self.family = name.to_string();
            self
        }

        pub fn build(self) -> FontProperty {
            let family_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontFamilyNameAttribute) };
            let family_name: CFString = self.family.parse().unwrap();
            let traits_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontTraitsAttribute) };
            let symbolic_traits_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontSymbolicTrait) };
            let traits = CFDictionary::from_CFType_pairs(&[(symbolic_traits_attr.as_CFType(), CFNumber::from(self.symbolic_traits as i32).as_CFType())]);
            let mut attributes = Vec::new();
            attributes.push((traits_attr, traits.as_CFType()));
            if self.family.len() != 0 {
                attributes.push((family_attr, family_name.as_CFType()));
            }
            let attributes = CFDictionary::from_CFType_pairs(&attributes);
            font_descriptor::new_from_attributes(&attributes)
        }
    }

    /// Get the binary data and index of a specific font
    pub fn get(config: &FontProperty) -> Option<(Vec<u8>, c_int)> {
        let mut buffer = Vec::new();
        let url: CFURL;
        unsafe {
            let value =
                CTFontDescriptorCopyAttribute(config.as_concrete_TypeRef(), kCTFontURLAttribute);
            assert!(!value.is_null());

            let value: CFType = TCFType::wrap_under_get_rule(value);
            assert!(value.instance_of::<CFURL>());
            url = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
        }
        let path = url.to_path().unwrap();
        match File::open(path).and_then(|mut f| f.read_to_end(&mut buffer)) {
            Ok(_) => Some((buffer, 0)),
            Err(_) => None,
        }
    }

    /// Query the names of all fonts installed in the system
    pub fn query_all() -> Vec<String> {
        core_text::font_collection::get_family_names()
            .iter()
            .map(|family_name| family_name.to_string())
            .collect()
    }

    /// Query the names of specifc fonts installed in the system
    pub fn query_specific(property: &mut FontProperty) -> Vec<String> {
        let descs: CFArray<CTFontDescriptor> = unsafe {
            let descs = CTFontDescriptorCreateMatchingFontDescriptors(
                property.as_concrete_TypeRef(),
                ptr::null(),
            );
            TCFType::wrap_under_create_rule(descs)
        };
        descs
            .iter()
            .map(|desc| desc.family_name())
            .collect::<Vec<_>>()
    }
}
<commit_msg>fix(macos): return None insteadof panic! when unable to get font<commit_after>// The MIT License (MIT)
// Copyright (c) font-loader Developers
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/// Font loading utilities for installed system fonts
pub mod system_fonts {
    use core_text::font_descriptor::*;
    use core_text::font_descriptor;
    use core_text;
    use std::fs::File;
    use std::mem;
    use std::ptr;
    use core_foundation::string::CFString;
    use core_foundation::number::CFNumber;
    use core_foundation::array::CFArray;
    use core_foundation::dictionary::CFDictionary;
    use core_foundation::base::{CFType, TCFType};
    use core_foundation::url::CFURL;
    use libc::c_int;
    use std::io::Read;
    /// The platform specific font properties
    pub type FontProperty = CTFontDescriptor;

    /// Builder for FontProperty
    pub struct FontPropertyBuilder {
        symbolic_traits: CTFontSymbolicTraits,
        family: String
    }

    impl FontPropertyBuilder {
        pub fn new() -> FontPropertyBuilder {
            FontPropertyBuilder{ symbolic_traits: 0, family: String::new()}
        }

        pub fn italic(mut self) -> FontPropertyBuilder {
            self.symbolic_traits |= kCTFontItalicTrait;
            self
        }

        pub fn oblique(self) -> FontPropertyBuilder {
            self.italic()
        }

        pub fn monospace(mut self) -> FontPropertyBuilder {
            self.symbolic_traits |= kCTFontMonoSpaceTrait;
            self
        }

        pub fn bold(mut self) -> FontPropertyBuilder {
            self.symbolic_traits |= kCTFontBoldTrait;
            self
        }

        pub fn family(mut self, name: &str) -> FontPropertyBuilder {
            self.family = name.to_string();
            self
        }

        pub fn build(self) -> FontProperty {
            let family_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontFamilyNameAttribute) };
            let family_name: CFString = self.family.parse().unwrap();
            let traits_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontTraitsAttribute) };
            let symbolic_traits_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontSymbolicTrait) };
            let traits = CFDictionary::from_CFType_pairs(&[(symbolic_traits_attr.as_CFType(), CFNumber::from(self.symbolic_traits as i32).as_CFType())]);
            let mut attributes = Vec::new();
            attributes.push((traits_attr, traits.as_CFType()));
            if self.family.len() != 0 {
                attributes.push((family_attr, family_name.as_CFType()));
            }
            let attributes = CFDictionary::from_CFType_pairs(&attributes);
            font_descriptor::new_from_attributes(&attributes)
        }
    }

    /// Get the binary data and index of a specific font
    pub fn get(config: &FontProperty) -> Option<(Vec<u8>, c_int)> {
        let mut buffer = Vec::new();
        let url: CFURL;
        unsafe {
            let value =
                CTFontDescriptorCopyAttribute(config.as_concrete_TypeRef(), kCTFontURLAttribute);

            if value.is_null() {
                return None
            }

            let value: CFType = TCFType::wrap_under_get_rule(value);
            if !value.instance_of::<CFURL>() {
                return None
            }
            url = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
        }
        if let Some(path) = url.to_path() {
            match File::open(path).and_then(|mut f| f.read_to_end(&mut buffer)) {
                Ok(_) => return Some((buffer, 0)),
                Err(_) => return None,
            }
        };
        return None
    }

    /// Query the names of all fonts installed in the system
    pub fn query_all() -> Vec<String> {
        core_text::font_collection::get_family_names()
            .iter()
            .map(|family_name| family_name.to_string())
            .collect()
    }

    /// Query the names of specifc fonts installed in the system
    pub fn query_specific(property: &mut FontProperty) -> Vec<String> {
        let descs: CFArray<CTFontDescriptor> = unsafe {
            let descs = CTFontDescriptorCreateMatchingFontDescriptors(
                property.as_concrete_TypeRef(),
                ptr::null(),
            );
            TCFType::wrap_under_create_rule(descs)
        };
        descs
            .iter()
            .map(|desc| desc.family_name())
            .collect::<Vec<_>>()
    }
}
<|endoftext|>


<commit_before>//! This module implements a simple asset loader and cache.
//!
//! While ggez offers functions to load raw game assets such as
//! music files, images, etc, it provides no facilities for managing
//! them.  Ideally you want to load all the assets you need at once,
//! hold on to them for a time (the course of a level for instance),
//! and then potentially ditch the ones you don't need.
//! This module offers cache-like functionality to do exactly this.
//!
//! It will return an `Rc` containing the item loaded, so multiple
//! items can safely access (read-only) instances of the same asset.

// TODO: This is not thread safe; should we offer one that it?
// TODO: Check out calx-resource:
// https://github.com/rsaarelm/calx/blob/master/calx-resource/src/lib.rs
// It has a) nifty macros to build these automatically,
// and b) an asset type that will serialize to a key, and then
// deserialize the key to that asset.  Very neat!  But also
// a bit labyrenthine.
// It DOES also make thread-safety work through thread_local!().

use std::collections::BTreeMap;
use std::collections::btree_map::{Entry, VacantEntry, OccupiedEntry};
use std::fmt::Debug;
use std::path::Path;
use std::rc::Rc;
use ggez;
use ggez::{Context, GameError, GameResult};
use ggez::graphics;

pub trait Loadable<K, E> {
    fn load(_key: &K) -> Result<Self, E> where Self: Sized;
}

pub trait StateLoadable<K, E, S> {
    fn load_state(_key: &K, &mut S) -> Result<Self, E> where Self: Sized;
}

#[derive(Debug)]
pub struct AssetCache<K, V>
    where K: Ord + Clone + Debug
{
    contents: BTreeMap<K, Rc<V>>,
}

impl<K, V> AssetCache<K, V>
    where K: Ord + Clone + Debug
{
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new() -> Self {
        let map = BTreeMap::new();
        AssetCache { contents: map }
    }

    /// Gets the given asset, loading it if necessary.
    // Oh my goodness getting the E type param to the
    // right place was amazingly difficult.
    pub fn get<E>(&mut self, key: &K) -> Result<Rc<V>, E>
        where V: Loadable<K, E>
    {
        if let Some(v) = self.contents.get(key) {
            return Ok(v.clone());
        };

        let v = V::load(key)?;
        let v_rc = Rc::new(v);
        self.contents.insert(key.clone(), v_rc.clone());
        Ok(v_rc)
    }

    pub fn get_mut<E, S>(&mut self, key: &K) -> Result<&mut Rc<V>, E>
        where V: Loadable<K, E>
    {
        // entry.or_insert_with() isn't quite powerful
        // enough 'cause it doesn't propegate results.  ;_;
        let entry = self.contents.entry(key.clone());
        match entry {
            Entry::Vacant(e) => {
                let v = V::load(key)?;
                let v_rc = Rc::new(v);
                Ok(e.insert(v_rc))
            }
            Entry::Occupied(e) => Ok(e.into_mut()),
        }
    }

    /// Gets the given asset, loading it if necessary.
    pub fn get_state<E, S>(&mut self, key: &K, state: &mut S) -> Result<Rc<V>, E>
        where V: StateLoadable<K, E, S>
    {
        if let Some(v) = self.contents.get(key) {
            return Ok(v.clone());
        };

        let v = V::load_state(key, state)?;
        let v_rc = Rc::new(v);
        self.contents.insert(key.clone(), v_rc.clone());
        Ok(v_rc)
    }

    pub fn get_state_mut<E, S>(&mut self, key: &K, state: &mut S) -> Result<&mut Rc<V>, E>
        where V: StateLoadable<K, E, S>
    {
        // entry.or_insert_with() isn't quite powerful
        // enough 'cause it doesn't propegate results.  ;_;
        let entry = self.contents.entry(key.clone());
        match entry {
            Entry::Vacant(e) => {
                let v = V::load_state(key, state)?;
                let v_rc = Rc::new(v);
                Ok(e.insert(v_rc))
            }
            Entry::Occupied(e) => Ok(e.into_mut()),
        }
    }

    /// Removes all assets from the cache
    /// and frees any excess memory it uses.
    pub fn clear(&mut self) {
        let map = BTreeMap::new();
        self.contents = map;
    }

    /// Returns true if the given asset is loaded.
    pub fn loaded(&self, key: &K) -> bool {
        self.contents.contains_key(key)
    }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload<E>(&mut self, keys: &[K])
        where V: Loadable<K, E>
    {
        for k in keys {
            let _ = self.get(k);
        }
    }

    /// Preloads objects that require a state to load.
    pub fn preload_state<E, S>(&mut self, keys: &[K], state: &mut S)
        where V: StateLoadable<K, E, S>
    {
        for k in keys {
            let _ = self.get_state(k, state);
        }
    }

    /// Gets an object but only if it already exists in the
    /// wossname.
    /// Returns an error if it is not.
    pub fn get_preload(&mut self, key: &K) -> GameResult<Rc<V>> {
        if let Some(val) = self.contents.get(key) {
            Ok(val.clone())
        } else {
            let errmsg = format!("Tried to get asset {:?} but it was not preloaded!", key);
            let err = GameError::ResourceNotFound(errmsg);
            Err(err)

        }
    }

    pub fn get_preload_mut(&mut self, key: &K) -> GameResult<&mut Rc<V>> {
        if let Some(val) = self.contents.get_mut(key) {
            Ok(val)
        } else {
            let errmsg = format!("Tried to get asset {:?} but it was not preloaded!", key);
            let err = GameError::ResourceNotFound(errmsg);
            Err(err)

        }
    }
}

impl<'a, K: AsRef<Path>> StateLoadable<K, GameError, ggez::Context<'a>> for ggez::graphics::Image {
    fn load_state(key: &K, ctx: &mut Context<'a>) -> GameResult<Self> {
        graphics::Image::new(ctx, key)
    }
}

mod tests {
    use super::*;
    #[cfg(test)]
    impl<'a> Loadable<&'a str, ()> for String {
        fn load(key: &&str) -> Result<String, ()> {
            Ok(key.to_string())
        }
    }

    // It would be nice to get rid of the double references here somehow,
    // but then AssetCache ends up with a type of <str, String>
    // and `str` is not sized so it always has to involve a reference.
    #[test]
    fn test_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        assert!(!a.loaded(&"foo"));
        let s1 = a.get(&"foo").unwrap();
        assert_eq!(*s1, "foo");
        assert!(a.loaded(&"foo"));
    }

    impl<'a> StateLoadable<&'a str, (), i32> for String {
        fn load_state(key: &&str, state: &mut i32) -> Result<String, ()> {
            *state += 1;
            Ok(key.to_string())
        }
    }

    #[test]
    fn test_stateful_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        let s = &mut 10;
        assert!(!a.loaded(&"foo"));
        let s1 = a.get_state(&"foo", s).unwrap();
        assert_eq!(*s1, "foo");
        assert_eq!(*s, 11);
        assert!(a.loaded(&"foo"));
    }

}
<commit_msg>Making a fancier asset manager!<commit_after>//! This module implements a simple asset loader and cache.
//!
//! While ggez offers functions to load raw game assets such as
//! music files, images, etc, it provides no facilities for managing
//! them.  Ideally you want to load all the assets you need at once,
//! hold on to them for a time (the course of a level for instance),
//! and then potentially ditch the ones you don't need.
//! This module offers cache-like functionality to do exactly this.
//!
//! It will return an `Rc` containing the item loaded, so multiple
//! items can safely access (read-only) instances of the same asset.

// TODO: This is not thread safe; should we offer one that it?
// TODO: Check out calx-resource:
// https://github.com/rsaarelm/calx/blob/master/calx-resource/src/lib.rs
// It has a) nifty macros to build these automatically,
// and b) an asset type that will serialize to a key, and then
// deserialize the key to that asset.  Very neat!  But also
// a bit labyrenthine.
// It DOES also make thread-safety work through thread_local!().

use std::collections::BTreeMap;
use std::collections::btree_map::{Entry, VacantEntry, OccupiedEntry};
use std::fmt::Debug;
use std::path::Path;
use std::rc::Rc;
use ggez;
use ggez::{Context, GameError, GameResult};
use ggez::graphics;

pub trait Loadable<K, E> {
    fn load(_key: &K) -> Result<Self, E> where Self: Sized;
}

pub trait StateLoadable<K, E, S> {
    fn load_state(_key: &K, &mut S) -> Result<Self, E> where Self: Sized;
}

#[derive(Debug)]
pub struct AssetCache<K, V>
    where K: Ord + Clone + Debug
{
    contents: BTreeMap<K, Rc<V>>,
}

impl<K, V> AssetCache<K, V>
    where K: Ord + Clone + Debug
{
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new() -> Self {
        let map = BTreeMap::new();
        AssetCache { contents: map }
    }

    /// Gets the given asset, loading it if necessary.
    // Oh my goodness getting the E type param to the
    // right place was amazingly difficult.
    pub fn get<E>(&mut self, key: &K) -> Result<Rc<V>, E>
        where V: Loadable<K, E>
    {
        if let Some(v) = self.contents.get(key) {
            return Ok(v.clone());
        };

        let v = V::load(key)?;
        let v_rc = Rc::new(v);
        self.contents.insert(key.clone(), v_rc.clone());
        Ok(v_rc)
    }

    pub fn get_mut<E, S>(&mut self, key: &K) -> Result<&mut Rc<V>, E>
        where V: Loadable<K, E>
    {
        // entry.or_insert_with() isn't quite powerful
        // enough 'cause it doesn't propegate results.  ;_;
        let entry = self.contents.entry(key.clone());
        match entry {
            Entry::Vacant(e) => {
                let v = V::load(key)?;
                let v_rc = Rc::new(v);
                Ok(e.insert(v_rc))
            }
            Entry::Occupied(e) => Ok(e.into_mut()),
        }
    }

    /// Gets the given asset, loading it if necessary.
    pub fn get_state<E, S>(&mut self, key: &K, state: &mut S) -> Result<Rc<V>, E>
        where V: StateLoadable<K, E, S>
    {
        if let Some(v) = self.contents.get(key) {
            return Ok(v.clone());
        };

        let v = V::load_state(key, state)?;
        let v_rc = Rc::new(v);
        self.contents.insert(key.clone(), v_rc.clone());
        Ok(v_rc)
    }

    pub fn get_state_mut<E, S>(&mut self, key: &K, state: &mut S) -> Result<&mut Rc<V>, E>
        where V: StateLoadable<K, E, S>
    {
        // entry.or_insert_with() isn't quite powerful
        // enough 'cause it doesn't propegate results.  ;_;
        let entry = self.contents.entry(key.clone());
        match entry {
            Entry::Vacant(e) => {
                let v = V::load_state(key, state)?;
                let v_rc = Rc::new(v);
                Ok(e.insert(v_rc))
            }
            Entry::Occupied(e) => Ok(e.into_mut()),
        }
    }

    /// Removes all assets from the cache
    /// and frees any excess memory it uses.
    pub fn clear(&mut self) {
        let map = BTreeMap::new();
        self.contents = map;
    }

    /// Returns true if the given asset is loaded.
    pub fn loaded(&self, key: &K) -> bool {
        self.contents.contains_key(key)
    }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload<E>(&mut self, keys: &[K])
        where V: Loadable<K, E>
    {
        for k in keys {
            let _ = self.get(k);
        }
    }

    /// Preloads objects that require a state to load.
    pub fn preload_state<E, S>(&mut self, keys: &[K], state: &mut S)
        where V: StateLoadable<K, E, S>
    {
        for k in keys {
            let _ = self.get_state(k, state);
        }
    }

    /// Gets an object but only if it already exists in the
    /// wossname.
    /// Returns an error if it is not.
    pub fn get_preload(&mut self, key: &K) -> GameResult<Rc<V>> {
        if let Some(val) = self.contents.get(key) {
            Ok(val.clone())
        } else {
            let errmsg = format!("Tried to get asset {:?} but it was not preloaded!", key);
            let err = GameError::ResourceNotFound(errmsg);
            Err(err)

        }
    }

    pub fn get_preload_mut(&mut self, key: &K) -> GameResult<&mut Rc<V>> {
        if let Some(val) = self.contents.get_mut(key) {
            Ok(val)
        } else {
            let errmsg = format!("Tried to get asset {:?} but it was not preloaded!", key);
            let err = GameError::ResourceNotFound(errmsg);
            Err(err)

        }
    }
}

impl<'a, K: AsRef<Path>> StateLoadable<K, GameError, ggez::Context<'a>> for ggez::graphics::Image {
    fn load_state(key: &K, ctx: &mut Context<'a>) -> GameResult<Self> {
        graphics::Image::new(ctx, key)
    }
}

/// An opaque asset handle that can be used for O(1) fetches
/// of assets.
#[derive(Debug, Copy, Clone)]
pub struct AssetHandle(usize);

#[derive(Debug)]
pub struct AssetCache2<K, V>
    where K: Ord + Clone + Debug
{
    handles: Vec<Rc<V>>,
    keys: BTreeMap<K, AssetHandle>,
    next_handle: usize,
}

impl<K, V> AssetCache2<K, V>
    where K: Ord + Clone + Debug
{
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new() -> Self {
        AssetCache2 {
            handles: Vec::new(),
            keys: BTreeMap::new(),
            next_handle: 0,
        }
    }

    fn new_handle(&mut self) -> AssetHandle {
        let i = self.next_handle;
        self.next_handle += 1;
        AssetHandle(i)
    }

    // Inserts the given asset into the handles vec at the given
    // location, and inserts the key into the key->handle mapping.
    // Performs asserts that will panic if something
    // gets out of sync (which should be impossible).
    fn bind_handle(&mut self, key: K, h: AssetHandle, value: Rc<V>) {
        let AssetHandle(i) = h;
        assert!(i == self.handles.len());
        self.handles.push(value);

        assert!(!self.keys.contains_key(&key));
        self.keys.insert(key, h);
    }

    // Adds a new item to the cache, returns an Rc reference to it
    // and an AssetHandle.
    fn add_item(&mut self, key: K, value: V) -> (AssetHandle, Rc<V>) {
        let handle = self.new_handle();
        let rc = Rc::new(value);
        self.bind_handle(key, handle, rc.clone());
        (handle, rc)
    }

    /// Retrieves an asset via its handle.
    /// This is always safe (and fast) because for a handle
    /// to be valid its object *must* exist in the cache.
    pub fn get(&self, handle: AssetHandle) -> Rc<V> {
        let AssetHandle(i) = handle;
        self.handles[i].clone()
    }

    // fn add_item_mut(&mut self, key: K, value: &mut V) -> (AssetHandle, Rc<&mut V>) {
    //     let entry = self.contents.entry(key.clone());
    //     match entry {
    //         Entry::Vacant(e) => {
    //             let v = V::load(key)?;
    //             let v_rc = Rc::new(v);
    //             Ok(e.insert(v_rc));
    //             Ok(self.add_item(key.clone(), v));
    //         }
    //         Entry::Occupied(e) => Ok(e.into_mut()),
    //     }

    // }

    /// Gets the given asset, loading it if necessary.
    /// Returns an Rc to the value, plus an AssetHandle
    /// which can be used to retrieve it quickly.
    // Oh my goodness getting the E type param to the
    // right place was amazingly difficult.
    pub fn get_key<E>(&mut self, key: &K) -> Result<(AssetHandle, Rc<V>), E>
        where V: Loadable<K, E>
    {
        if let Some(handle) = self.keys.get(key) {
            return Ok((*handle, self.get(*handle)));
        };

        let v = V::load(key)?;
        let res = self.add_item(key.clone(), v);
        Ok(res)
    }

    // pub fn get_mut<E, S>(&mut self, key: &K) -> Result<&mut Rc<V>, E>
    //     where V: Loadable<K, E>
    // {
    //     // entry.or_insert_with() isn't quite powerful
    //     // enough 'cause it doesn't propegate Results.  ;_;
    //     let entry = self.contents.entry(key.clone());
    //     match entry {
    //         Entry::Vacant(e) => {
    //             let v = V::load(key)?;
    //             let v_rc = Rc::new(v);
    //             Ok(e.insert(v_rc));
    //             Ok(self.add_item(key.clone(), v));
    //         }
    //         Entry::Occupied(e) => Ok(e.into_mut()),
    //     }
    // }

    // /// Gets the given asset, loading it if necessary.
    // pub fn get_state<E, S>(&mut self, key: &K, state: &mut S) -> Result<Rc<V>, E>
    //     where V: StateLoadable<K, E, S>
    // {
    //     if let Some(v) = self.contents.get(key) {
    //         return Ok(v.clone());
    //     };

    //     let v = V::load_state(key, state)?;
    //     let v_rc = Rc::new(v);
    //     self.contents.insert(key.clone(), v_rc.clone());
    //     Ok(v_rc)
    // }

    // pub fn get_state_mut<E, S>(&mut self, key: &K, state: &mut S) -> Result<&mut Rc<V>, E>
    //     where V: StateLoadable<K, E, S>
    // {
    //     // entry.or_insert_with() isn't quite powerful
    //     // enough 'cause it doesn't propegate results.  ;_;
    //     let entry = self.contents.entry(key.clone());
    //     match entry {
    //         Entry::Vacant(e) => {
    //             let v = V::load_state(key, state)?;
    //             let v_rc = Rc::new(v);
    //             Ok(e.insert(v_rc))
    //         }
    //         Entry::Occupied(e) => Ok(e.into_mut()),
    //     }
    // }

    // /// Removes all assets from the cache
    // /// and frees any excess memory it uses.
    // pub fn clear(&mut self) {
    //     let map = BTreeMap::new();
    //     self.contents = map;
    // }

    // /// Returns true if the given asset is loaded.
    // pub fn loaded(&self, key: &K) -> bool {
    //     self.contents.contains_key(key)
    // }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload<E>(&mut self, keys: &[K])
        where V: Loadable<K, E>
    {
        for k in keys {
            let _ = self.get_key(k);
        }
    }

    // /// Preloads objects that require a state to load.
    // pub fn preload_state<E, S>(&mut self, keys: &[K], state: &mut S)
    //     where V: StateLoadable<K, E, S>
    // {
    //     for k in keys {
    //         let _ = self.get_state(k, state);
    //     }
    // }

    // /// Gets an object but only if it already exists in the
    // /// wossname.
    // /// Returns an error if it is not.
    // pub fn get_preload(&mut self, key: &K) -> GameResult<Rc<V>> {
    //     if let Some(val) = self.contents.get(key) {
    //         Ok(val.clone())
    //     } else {
    //         let errmsg = format!("Tried to get asset {:?} but it was not preloaded!", key);
    //         let err = GameError::ResourceNotFound(errmsg);
    //         Err(err)

    //     }
    // }

    // pub fn get_preload_mut(&mut self, key: &K) -> GameResult<&mut Rc<V>> {
    //     if let Some(val) = self.contents.get_mut(key) {
    //         Ok(val)
    //     } else {
    //         let errmsg = format!("Tried to get asset {:?} but it was not preloaded!", key);
    //         let err = GameError::ResourceNotFound(errmsg);
    //         Err(err)

    //     }
    // }
}

mod tests {
    use super::*;
    #[cfg(test)]
    impl<'a> Loadable<&'a str, ()> for String {
        fn load(key: &&str) -> Result<String, ()> {
            Ok(key.to_string())
        }
    }

    // It would be nice to get rid of the double references here somehow,
    // but then AssetCache ends up with a type of <str, String>
    // and `str` is not sized so it always has to involve a reference.
    #[test]
    fn test_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        assert!(!a.loaded(&"foo"));
        let s1 = a.get(&"foo").unwrap();
        assert_eq!(*s1, "foo");
        assert!(a.loaded(&"foo"));
    }

    impl<'a> StateLoadable<&'a str, (), i32> for String {
        fn load_state(key: &&str, state: &mut i32) -> Result<String, ()> {
            *state += 1;
            Ok(key.to_string())
        }
    }

    #[test]
    fn test_stateful_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        let s = &mut 10;
        assert!(!a.loaded(&"foo"));
        let s1 = a.get_state(&"foo", s).unwrap();
        assert_eq!(*s1, "foo");
        assert_eq!(*s, 11);
        assert!(a.loaded(&"foo"));
    }

}
<|endoftext|>