<commit_before>#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate nom;
extern crate quote;
extern crate syn;

#[cfg(feature = "serde-json")]
extern crate serde;
#[cfg(feature = "serde-json")]
extern crate serde_json;

pub use escaping::MarkupDisplay;
pub use errors::{Error, Result};
pub mod filters;
pub mod path;

mod escaping;
mod generator;
mod input;
mod parser;

use input::Print;
use parser::{Node, Macro};

use std::borrow::Cow;
use std::collections::HashMap;
use std::path::Path;

/// Takes a `syn::DeriveInput` and generates source code for it
///
/// Reads the metadata from the `template()` attribute to get the template
/// metadata, then fetches the source from the filesystem. The source is
/// parsed, and the parse tree is fed to the code generator. Will print
/// the parse tree and/or generated source according to the `print` key's
/// value as passed to the `template()` attribute.
pub fn build_template(ast: &syn::DeriveInput) -> String {
    let data = input::TemplateInput::new(ast);
    let nodes = parser::parse(data.source.as_ref());
    let imports = Imports::new(&nodes, &data.path);
    if data.meta.print == Print::Ast || data.meta.print == Print::All {
        println!("{:?}", nodes);
    }
    let code = generator::generate(&data, &nodes, &imports.macro_map());
    if data.meta.print == Print::Code || data.meta.print == Print::All {
        println!("{}", code);
    }
    code
}

pub struct Imports<'a> {
    pub sources: Vec<Cow<'a, str>>
}

impl <'a> Imports<'a> {
    pub fn new(parent_nodes: &'a [Node], parent_path: &'a Path) -> Imports<'a> {
        let sources = parent_nodes.iter().filter_map(|n| {
            match *n {
                Node::Import(_, ref import_path) => {
                    let path = path::find_template_from_path(import_path, Some(parent_path));
                    let src = path::get_template_source(&path);
                    Some(Cow::Owned(src))
                },
                _ => None,
            }
        }).collect();
        Imports { sources }
    }

    pub fn parse(&'a self) -> HashMap<&'a str, Macro<'a>> {
        self.sources.iter()
            .flat_map(|s| parser::parse(s.as_ref()))
            .filter_map(|n| {
                match n {
                    Node::Macro(name, m) => Some((name, m)),
                    _ => None,
                }})
            .collect()
    }
}

mod errors {
    error_chain! {
        foreign_links {
            Fmt(::std::fmt::Error);
            Json(::serde_json::Error) #[cfg(feature = "serde-json")];
        }
    }
}
<commit_msg>Rename parse() method to macro_map()<commit_after>#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate nom;
extern crate quote;
extern crate syn;

#[cfg(feature = "serde-json")]
extern crate serde;
#[cfg(feature = "serde-json")]
extern crate serde_json;

pub use escaping::MarkupDisplay;
pub use errors::{Error, Result};
pub mod filters;
pub mod path;

mod escaping;
mod generator;
mod input;
mod parser;

use input::Print;
use parser::{Node, Macro};

use std::borrow::Cow;
use std::collections::HashMap;
use std::path::Path;

/// Takes a `syn::DeriveInput` and generates source code for it
///
/// Reads the metadata from the `template()` attribute to get the template
/// metadata, then fetches the source from the filesystem. The source is
/// parsed, and the parse tree is fed to the code generator. Will print
/// the parse tree and/or generated source according to the `print` key's
/// value as passed to the `template()` attribute.
pub fn build_template(ast: &syn::DeriveInput) -> String {
    let data = input::TemplateInput::new(ast);
    let nodes = parser::parse(data.source.as_ref());
    let imports = Imports::new(&nodes, &data.path);
    if data.meta.print == Print::Ast || data.meta.print == Print::All {
        println!("{:?}", nodes);
    }
    let code = generator::generate(&data, &nodes, &imports.macro_map());
    if data.meta.print == Print::Code || data.meta.print == Print::All {
        println!("{}", code);
    }
    code
}

pub struct Imports<'a> {
    pub sources: Vec<Cow<'a, str>>
}

impl <'a> Imports<'a> {
    pub fn new(parent_nodes: &'a [Node], parent_path: &'a Path) -> Imports<'a> {
        let sources = parent_nodes.iter().filter_map(|n| {
            match *n {
                Node::Import(_, ref import_path) => {
                    let path = path::find_template_from_path(import_path, Some(parent_path));
                    let src = path::get_template_source(&path);
                    Some(Cow::Owned(src))
                },
                _ => None,
            }
        }).collect();
        Imports { sources }
    }

    pub fn macro_map(&'a self) -> HashMap<&'a str, Macro<'a>> {
        self.sources.iter()
            .flat_map(|s| parser::parse(s.as_ref()))
            .filter_map(|n| {
                match n {
                    Node::Macro(name, m) => Some((name, m)),
                    _ => None,
                }})
            .collect()
    }
}

mod errors {
    error_chain! {
        foreign_links {
            Fmt(::std::fmt::Error);
            Json(::serde_json::Error) #[cfg(feature = "serde-json")];
        }
    }
}
<|endoftext|>


<commit_before>use std::num;
use std::vec;
use addressable::Addressable;

pub struct Ram<ADDR> {
	data: ~[u8],
}

impl<ADDR: Int> Ram<ADDR> {
	pub fn new (size: uint) -> ~Ram<ADDR> {
		~Ram { data: vec::from_elem(size, 0) }
	}
}

impl<ADDR: Int> Addressable<ADDR, u8> for Ram<ADDR> {
	pub fn get (&self, addr: ADDR) -> u8 {
		let i: uint = num::cast(addr);
		if i >= self.data.len() { fail!("memory: read beyond memory bounds ($%x >= $%x)", i, self.data.len()); }
		self.data[i]
	}

	pub fn set (&mut self, addr: ADDR, data: u8) {
		let i: uint = num::cast(addr);
		if i >= self.data.len() { fail!("memory: write beyond memory bounds ($%x >= $%x)", i, self.data.len()); }
		self.data[i] = data;
	}
}

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

	#[test]
	fn test () {
		let mut memory = Ram::new(1024);
		memory.set(0x0123, 0x55);
		assert_eq!(memory.get(0x0123), 0x55);
	}
}
<commit_msg>Fixed ram failure messages<commit_after>use std::num;
use std::vec;
use addressable::Addressable;

pub struct Ram<ADDR> {
	data: ~[u8],
}

impl<ADDR: Int> Addressable<ADDR, u8> for Ram<ADDR> {
	pub fn get (&self, addr: ADDR) -> u8 {
		let i: uint = num::cast(addr);
		if i >= self.data.len() { fail!("ram: read beyond memory bounds ($%x >= $%x)", i, self.data.len()); }
		self.data[i]
	}

	pub fn set (&mut self, addr: ADDR, data: u8) {
		let i: uint = num::cast(addr);
		if i >= self.data.len() { fail!("ram: write beyond memory bounds ($%x >= $%x)", i, self.data.len()); }
		self.data[i] = data;
	}
}

impl<ADDR: Int> Ram<ADDR> {
	pub fn new (size: uint) -> ~Ram<ADDR> {
		~Ram { data: vec::from_elem(size, 0) }
	}
}

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

	#[test]
	fn test () {
		let mut memory = Ram::new(1024);
		memory.set(0x0123, 0x55);
		assert_eq!(memory.get(0x0123), 0x55);
	}
}
<|endoftext|>


<commit_before>use std::fmt;

/// The selector is used to read a property value from the `Theme`.
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Selector {
    /// Represents the key of a style.
    pub style: Option<String>,

    // Used to reference the state property list of the given style. The state on the top of the vector is the active one.
    states: Vec<String>,

    /// Check if the selector is dirty.
    dirty: bool,
}

impl Selector {
    /// Creates a new selector with the given style key.
    pub fn new(style: impl Into<String>) -> Self {
        Selector {
            style: Some(style.into()),
            states: vec![],
            dirty: true,
        }
    }

    /// Returns a reference to an active state.
    pub fn active_state(&self) -> Option<&String> {
        if self.states.is_empty() {
            return None;
        }

        self.states.get(self.states.len() - 1)
    }

    /// Pushes a state to the states vector.
    pub fn push_state(&mut self, state: impl Into<String>) {
        self.states.push(state.into());
        self.dirty = true;
    }

    /// Removes all instances of the the give state from the vector and returns it.
    pub fn remove_state(&mut self, state: impl Into<String>) -> Option<String> {
        let state: String = state.into();

        if !state.is_empty() && self.states.contains(&state) {
            while let Some(pos) = self.states.iter().position(|x| *x == state) {
                self.states.remove(pos);
            }

            self.dirty = true;
            return Some(state);
        }

        None
    }

    /// Removes the last state from a vector and returns it, or None if it is empty. If there is a new last vector it will be the new active state.
    pub fn pop_state(&mut self) -> Option<String> {
        self.dirty = true;
        self.states.pop()
    }

    /// Gets the dirty flag.
    pub fn dirty(&self) -> bool {
        self.dirty
    }

    /// Sets the dirty flag.
    pub fn set_dirty(&mut self, dirty: bool) {
        self.dirty = dirty;
    }

    /// Check if the selector has the given state.
    pub fn has_state(&self, state: &str) -> bool {
        self.states.contains(&state.to_string())
    }
}

impl fmt::Display for Selector {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(style) = &self.style {
            return write!(f, "Selector ( style: {} )", style);
        }
        write!(f, "Selector ( empty )")
    }
}

impl From<&str> for Selector {
    fn from(s: &str) -> Self {
        Selector::new(s)
    }
}

impl From<String> for Selector {
    fn from(s: String) -> Self {
        Selector::new(s)
    }
}
<commit_msg>typo correction<commit_after>use std::fmt;

/// The selector is used to read a property value from the `Theme`.
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Selector {
    /// Represents the key of a style.
    pub style: Option<String>,

    // Used to reference the state property list of the given style. The state on the top of the vector is the active one.
    states: Vec<String>,

    /// Check if the selector is dirty.
    dirty: bool,
}

impl Selector {
    /// Creates a new selector with the given style key.
    pub fn new(style: impl Into<String>) -> Self {
        Selector {
            style: Some(style.into()),
            states: vec![],
            dirty: true,
        }
    }

    /// Returns a reference to an active state.
    pub fn active_state(&self) -> Option<&String> {
        if self.states.is_empty() {
            return None;
        }

        self.states.get(self.states.len() - 1)
    }

    /// Pushes a state to the states vector.
    pub fn push_state(&mut self, state: impl Into<String>) {
        self.states.push(state.into());
        self.dirty = true;
    }

    /// Removes all instances of the give state from the vector and returns it.
    pub fn remove_state(&mut self, state: impl Into<String>) -> Option<String> {
        let state: String = state.into();

        if !state.is_empty() && self.states.contains(&state) {
            while let Some(pos) = self.states.iter().position(|x| *x == state) {
                self.states.remove(pos);
            }

            self.dirty = true;
            return Some(state);
        }

        None
    }

    /// Removes the last state from a vector and returns it, or None if it is empty. If there is a new last vector it will be the new active state.
    pub fn pop_state(&mut self) -> Option<String> {
        self.dirty = true;
        self.states.pop()
    }

    /// Gets the dirty flag.
    pub fn dirty(&self) -> bool {
        self.dirty
    }

    /// Sets the dirty flag.
    pub fn set_dirty(&mut self, dirty: bool) {
        self.dirty = dirty;
    }

    /// Check if the selector has the given state.
    pub fn has_state(&self, state: &str) -> bool {
        self.states.contains(&state.to_string())
    }
}

impl fmt::Display for Selector {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if let Some(style) = &self.style {
            return write!(f, "Selector ( style: {} )", style);
        }
        write!(f, "Selector ( empty )")
    }
}

impl From<&str> for Selector {
    fn from(s: &str) -> Self {
        Selector::new(s)
    }
}

impl From<String> for Selector {
    fn from(s: String) -> Self {
        Selector::new(s)
    }
}
<|endoftext|>


<commit_before>use parser::{Cond, Expr, Node, Target, WS};
use std::str;
use std::collections::HashSet;
use syn;

fn annotations(generics: &syn::Generics) -> String {
    if generics.lifetimes.len() < 1 {
        return String::new();
    }
    let mut res = String::new();
    res.push('<');
    for lt in &generics.lifetimes {
        res.push_str(lt.lifetime.ident.as_ref());
    }
    res.push('>');
    res
}

fn path_as_identifier(s: &str) -> String {
    let mut res = String::new();
    for c in s.chars() {
        if c.is_alphanumeric() {
            res.push(c);
        } else {
            res.push_str(&format!("{:x}", c as u32));
        }
    }
    res
}

struct Generator<'a> {
    buf: String,
    indent: u8,
    start: bool,
    locals: HashSet<String>,
    next_ws: Option<&'a str>,
    skip_ws: bool,
}

impl<'a> Generator<'a> {

    fn new() -> Generator<'a> {
        Generator {
            buf: String::new(),
            indent: 0,
            start: true,
            locals: HashSet::new(),
            next_ws: None,
            skip_ws: false,
        }
    }

    fn indent(&mut self) {
        self.indent += 1;
    }

    fn dedent(&mut self) {
        self.indent -= 1;
    }

    fn write(&mut self, s: &str) {
        if self.start {
            for _ in 0..(self.indent * 4) {
                self.buf.push(' ');
            }
            self.start = false;
        }
        self.buf.push_str(s);
    }

    fn writeln(&mut self, s: &str) {
        if s.is_empty() {
            return;
        }
        if s == "}" {
            self.dedent();
        }
        self.write(s);
        if s.ends_with('{') {
            self.indent();
        }
        self.buf.push('\n');
        self.start = true;
    }

    fn flush_ws(&mut self, ws: &WS) {
        if self.next_ws.is_some() && !ws.0 {
            let val = self.next_ws.unwrap();
            if !val.is_empty() {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      val));
            }
        }
        self.next_ws = None;
    }

    fn prepare_ws(&mut self, ws: &WS) {
        self.skip_ws = ws.1;
    }

    fn handle_ws(&mut self, ws: &WS) {
        self.flush_ws(ws);
        self.prepare_ws(ws);
    }

    fn visit_num_lit(&mut self, s: &str) {
        self.write(s);
    }

    fn visit_str_lit(&mut self, s: &str) {
        self.write(&format!("\"{}\"", s));
    }

    fn visit_var(&mut self, s: &str) {
        if self.locals.contains(s) {
            self.write(s);
        } else {
            self.write(&format!("self.{}", s));
        }
    }

    fn visit_attr(&mut self, obj: &Expr, attr: &str) {
        if let Expr::Var(name) = *obj {
            if name == "loop" {
                self.write("_loop_index");
                if attr == "index" {
                    self.write(" + 1");
                    return;
                } else if attr == "index0" {
                    return;
                } else {
                    panic!("unknown loop variable");
                }
            }
        }
        self.visit_expr(obj);
        self.write(&format!(".{}", attr));
    }

    fn visit_filter(&mut self, name: &str, args: &[Expr]) {
        if name == "format" {
            self.write("format!(");
        } else {
            self.write(&format!("askama::filters::{}(&", name));
        }

        for (i, arg) in args.iter().enumerate() {
            if i > 0 {
                self.write(", &");
            }
            self.visit_expr(arg);
        }
        self.write(")");
    }

    fn visit_binop(&mut self, op: &str, left: &Expr, right: &Expr) {
        self.visit_expr(left);
        self.write(&format!(" {} ", op));
        self.visit_expr(right);
    }

    fn visit_group(&mut self, inner: &Expr) {
        self.write("(");
        self.visit_expr(inner);
        self.write(")");
    }

    fn visit_call(&mut self, obj: &Expr, method: &str, args: &[Expr]) {
        self.visit_expr(obj);
        self.write(&format!(".{}(", method));
        for (i, arg) in args.iter().enumerate() {
            if i > 0 {
                self.write(", ");
            }
            self.visit_expr(arg);
        }
        self.write(")");
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match *expr {
            Expr::NumLit(s) => self.visit_num_lit(s),
            Expr::StrLit(s) => self.visit_str_lit(s),
            Expr::Var(s) => self.visit_var(s),
            Expr::Attr(ref obj, name) => self.visit_attr(obj, name),
            Expr::Filter(name, ref args) => self.visit_filter(name, args),
            Expr::BinOp(op, ref left, ref right) =>
                self.visit_binop(op, left, right),
            Expr::Group(ref inner) => self.visit_group(inner),
            Expr::Call(ref obj, method, ref args) =>
                self.visit_call(obj, method, args),
        }
    }

    fn visit_target_single(&mut self, name: &str) -> Vec<String> {
        vec![name.to_string()]
    }

    fn visit_target(&mut self, target: &Target) -> Vec<String> {
        match *target {
            Target::Name(s) => { self.visit_target_single(s) },
        }
    }

    fn write_lit(&mut self, lws: &'a str, val: &str, rws: &'a str) {
        assert!(self.next_ws.is_none());
        if !lws.is_empty() {
            if self.skip_ws {
                self.skip_ws = false;
            } else if val.is_empty() {
                assert!(rws.is_empty());
                self.next_ws = Some(lws);
            } else {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      lws));
            }
        }
        if !val.is_empty() {
            self.writeln(&format!("writer.write_str({:#?}).unwrap();", val));
        }
        if !rws.is_empty() {
            self.next_ws = Some(rws);
        }
    }

    fn write_expr(&mut self, ws: &WS, s: &Expr) {
        self.handle_ws(ws);
        self.write("writer.write_fmt(format_args!(\"{}\", ");
        self.visit_expr(s);
        self.writeln(")).unwrap();");
    }

    fn write_cond(&mut self, conds: &'a [Cond], ws: &WS) {
        for (i, &(ref cws, ref cond, ref nodes)) in conds.iter().enumerate() {
            self.handle_ws(cws);
            match *cond {
                Some(ref expr) => {
                    if i == 0 {
                        self.write("if ");
                    } else {
                        self.dedent();
                        self.write("} else if ");
                    }
                    self.visit_expr(expr);
                },
                None => {
                    self.dedent();
                    self.write("} else");
                },
            }
            self.writeln(" {");
            self.handle(nodes);
        }
        self.handle_ws(ws);
        self.writeln("}");
    }

    fn write_loop(&mut self, ws1: &WS, var: &Target, iter: &Expr,
                  body: &'a [Node], ws2: &WS) {
        self.handle_ws(ws1);
        self.write("for (_loop_index, ");
        let targets = self.visit_target(var);
        for name in &targets {
            self.locals.insert(name.clone());
            self.write(name);
        }
        self.write(") in (&");
        self.visit_expr(iter);
        self.writeln(").into_iter().enumerate() {");

        self.handle(body);
        self.handle_ws(ws2);
        self.writeln("}");
        for name in &targets {
            self.locals.remove(name);
        }
    }

    fn write_block(&mut self, ws1: &WS, name: &str, ws2: &WS) {
        self.flush_ws(ws1);
        self.writeln(&format!("timpl.render_block_{}_to(writer);", name));
        self.prepare_ws(ws2);
    }

    fn write_block_def(&mut self, ws1: &WS, name: &str, nodes: &'a [Node],
                       ws2: &WS) {
        self.writeln("#[allow(unused_variables)]");
        self.writeln(&format!(
            "fn render_block_{}_to(&self, writer: &mut std::fmt::Write) {{",
            name));
        self.prepare_ws(ws1);
        self.handle(nodes);
        self.flush_ws(ws2);
        self.writeln("}");
    }

    fn handle(&mut self, nodes: &'a [Node]) {
        for n in nodes {
            match *n {
                Node::Lit(lws, val, rws) => { self.write_lit(lws, val, rws); }
                Node::Comment() => {},
                Node::Expr(ref ws, ref val) => { self.write_expr(ws, val); },
                Node::Cond(ref conds, ref ws) => {
                    self.write_cond(conds, ws);
                },
                Node::Loop(ref ws1, ref var, ref iter, ref body, ref ws2) => {
                    self.write_loop(ws1, var, iter, body, ws2);
                },
                Node::Block(ref ws1, name, ref ws2) => {
                    self.write_block(ws1, name, ws2);
                },
                Node::BlockDef(ref ws1, name, ref block_nodes, ref ws2) => {
                    self.write_block_def(ws1, name, block_nodes, ws2);
                }
                Node::Extends(_) => {
                    panic!("no extends or block definition allowed in content");
                },
            }
        }
    }

    fn write_header(&mut self, ast: &syn::DeriveInput,
                    trait_suffix: Option<&str>) {
        let anno = annotations(&ast.generics);
        let name = if trait_suffix.is_some() {
            format!("TraitFrom{}", trait_suffix.unwrap())
        } else {
            "askama::Template".to_string()
        };
        self.writeln(&format!("impl{} {} for {}{} {{",
                              anno, &name, ast.ident.as_ref(), anno));
    }

    fn impl_template(&mut self, ast: &syn::DeriveInput, nodes: &'a [Node]) {
        self.write_header(ast, None);
        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.handle(nodes);
        self.flush_ws(&WS(false, false));
        self.writeln("}");
        self.writeln("}");
    }

    fn impl_trait(&mut self, ast: &syn::DeriveInput, base: &str,
                  blocks: &'a [Node], nodes: Option<&'a [Node]>) {
        self.write_header(ast, Some(&path_as_identifier(base)));
        self.handle(blocks);

        self.writeln("#[allow(unused_variables)]");
        let trait_name = format!("TraitFrom{}", path_as_identifier(base));
        self.writeln(&format!(
            "fn render_trait_to(&self, timpl: &{}, writer: &mut std::fmt::Write) {{",
            trait_name));

        if let Some(nodes) = nodes {
            self.handle(nodes);
            self.flush_ws(&WS(false, false));
        } else {
            self.writeln("self._parent.render_trait_to(self, writer);");
        }

        self.writeln("}");
        self.flush_ws(&WS(false, false));
        self.writeln("}");
    }

    fn impl_template_for_trait(&mut self, ast: &syn::DeriveInput, derived: bool) {
        self.write_header(ast, None);
        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        if derived {
            self.writeln("self._parent.render_trait_to(self, writer);");
        } else {
            self.writeln("self.render_trait_to(self, writer);");
        }
        self.writeln("}");
        self.writeln("}");
    }

    fn define_trait(&mut self, path: &str, block_names: &[&str]) {
        let trait_name = format!("TraitFrom{}", path_as_identifier(path));
        self.writeln(&format!("trait {} {{", &trait_name));

        for bname in block_names {
            self.writeln(&format!(
                "fn render_block_{}_to(&self, writer: &mut std::fmt::Write);",
                bname));
        }
        self.writeln(&format!(
            "fn render_trait_to(&self, timpl: &{}, writer: &mut std::fmt::Write);",
            trait_name));

        self.writeln("}");
    }

    fn result(self) -> String {
        self.buf
    }

}

pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> String {
    let mut base: Option<Expr> = None;
    let mut blocks = Vec::new();
    let mut block_names = Vec::new();
    let mut content = Vec::new();
    for n in nodes.drain(..) {
        match n {
            Node::Extends(path) => {
                match base {
                    Some(_) => panic!("multiple extend blocks found"),
                    None => { base = Some(path); },
                }
            },
            Node::BlockDef(ws1, name, _, ws2) => {
                blocks.push(n);
                block_names.push(name);
                content.push(Node::Block(ws1, name, ws2));
            },
            _ => { content.push(n); },
        }
    }

    let mut gen = Generator::new();
    if !blocks.is_empty() {
        if base.is_none() {
            gen.define_trait(path, &block_names);
        }
        let tmpl_path = match base {
            Some(Expr::StrLit(base_path)) => { base_path },
            _ => { path },
        };
        let trait_nodes = if base.is_none() { Some(&content[..]) } else { None };
        gen.impl_trait(ast, tmpl_path, &blocks, trait_nodes);
        gen.impl_template_for_trait(ast, base.is_some());
    } else {
        gen.impl_template(ast, &content);
    }
    gen.result()
}
<commit_msg>Inline annotations() helper into write_header()<commit_after>use parser::{Cond, Expr, Node, Target, WS};
use std::str;
use std::collections::HashSet;
use syn;

fn path_as_identifier(s: &str) -> String {
    let mut res = String::new();
    for c in s.chars() {
        if c.is_alphanumeric() {
            res.push(c);
        } else {
            res.push_str(&format!("{:x}", c as u32));
        }
    }
    res
}

struct Generator<'a> {
    buf: String,
    indent: u8,
    start: bool,
    locals: HashSet<String>,
    next_ws: Option<&'a str>,
    skip_ws: bool,
}

impl<'a> Generator<'a> {

    fn new() -> Generator<'a> {
        Generator {
            buf: String::new(),
            indent: 0,
            start: true,
            locals: HashSet::new(),
            next_ws: None,
            skip_ws: false,
        }
    }

    fn indent(&mut self) {
        self.indent += 1;
    }

    fn dedent(&mut self) {
        self.indent -= 1;
    }

    fn write(&mut self, s: &str) {
        if self.start {
            for _ in 0..(self.indent * 4) {
                self.buf.push(' ');
            }
            self.start = false;
        }
        self.buf.push_str(s);
    }

    fn writeln(&mut self, s: &str) {
        if s.is_empty() {
            return;
        }
        if s == "}" {
            self.dedent();
        }
        self.write(s);
        if s.ends_with('{') {
            self.indent();
        }
        self.buf.push('\n');
        self.start = true;
    }

    fn flush_ws(&mut self, ws: &WS) {
        if self.next_ws.is_some() && !ws.0 {
            let val = self.next_ws.unwrap();
            if !val.is_empty() {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      val));
            }
        }
        self.next_ws = None;
    }

    fn prepare_ws(&mut self, ws: &WS) {
        self.skip_ws = ws.1;
    }

    fn handle_ws(&mut self, ws: &WS) {
        self.flush_ws(ws);
        self.prepare_ws(ws);
    }

    fn visit_num_lit(&mut self, s: &str) {
        self.write(s);
    }

    fn visit_str_lit(&mut self, s: &str) {
        self.write(&format!("\"{}\"", s));
    }

    fn visit_var(&mut self, s: &str) {
        if self.locals.contains(s) {
            self.write(s);
        } else {
            self.write(&format!("self.{}", s));
        }
    }

    fn visit_attr(&mut self, obj: &Expr, attr: &str) {
        if let Expr::Var(name) = *obj {
            if name == "loop" {
                self.write("_loop_index");
                if attr == "index" {
                    self.write(" + 1");
                    return;
                } else if attr == "index0" {
                    return;
                } else {
                    panic!("unknown loop variable");
                }
            }
        }
        self.visit_expr(obj);
        self.write(&format!(".{}", attr));
    }

    fn visit_filter(&mut self, name: &str, args: &[Expr]) {
        if name == "format" {
            self.write("format!(");
        } else {
            self.write(&format!("askama::filters::{}(&", name));
        }

        for (i, arg) in args.iter().enumerate() {
            if i > 0 {
                self.write(", &");
            }
            self.visit_expr(arg);
        }
        self.write(")");
    }

    fn visit_binop(&mut self, op: &str, left: &Expr, right: &Expr) {
        self.visit_expr(left);
        self.write(&format!(" {} ", op));
        self.visit_expr(right);
    }

    fn visit_group(&mut self, inner: &Expr) {
        self.write("(");
        self.visit_expr(inner);
        self.write(")");
    }

    fn visit_call(&mut self, obj: &Expr, method: &str, args: &[Expr]) {
        self.visit_expr(obj);
        self.write(&format!(".{}(", method));
        for (i, arg) in args.iter().enumerate() {
            if i > 0 {
                self.write(", ");
            }
            self.visit_expr(arg);
        }
        self.write(")");
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match *expr {
            Expr::NumLit(s) => self.visit_num_lit(s),
            Expr::StrLit(s) => self.visit_str_lit(s),
            Expr::Var(s) => self.visit_var(s),
            Expr::Attr(ref obj, name) => self.visit_attr(obj, name),
            Expr::Filter(name, ref args) => self.visit_filter(name, args),
            Expr::BinOp(op, ref left, ref right) =>
                self.visit_binop(op, left, right),
            Expr::Group(ref inner) => self.visit_group(inner),
            Expr::Call(ref obj, method, ref args) =>
                self.visit_call(obj, method, args),
        }
    }

    fn visit_target_single(&mut self, name: &str) -> Vec<String> {
        vec![name.to_string()]
    }

    fn visit_target(&mut self, target: &Target) -> Vec<String> {
        match *target {
            Target::Name(s) => { self.visit_target_single(s) },
        }
    }

    fn write_lit(&mut self, lws: &'a str, val: &str, rws: &'a str) {
        assert!(self.next_ws.is_none());
        if !lws.is_empty() {
            if self.skip_ws {
                self.skip_ws = false;
            } else if val.is_empty() {
                assert!(rws.is_empty());
                self.next_ws = Some(lws);
            } else {
                self.writeln(&format!("writer.write_str({:#?}).unwrap();",
                                      lws));
            }
        }
        if !val.is_empty() {
            self.writeln(&format!("writer.write_str({:#?}).unwrap();", val));
        }
        if !rws.is_empty() {
            self.next_ws = Some(rws);
        }
    }

    fn write_expr(&mut self, ws: &WS, s: &Expr) {
        self.handle_ws(ws);
        self.write("writer.write_fmt(format_args!(\"{}\", ");
        self.visit_expr(s);
        self.writeln(")).unwrap();");
    }

    fn write_cond(&mut self, conds: &'a [Cond], ws: &WS) {
        for (i, &(ref cws, ref cond, ref nodes)) in conds.iter().enumerate() {
            self.handle_ws(cws);
            match *cond {
                Some(ref expr) => {
                    if i == 0 {
                        self.write("if ");
                    } else {
                        self.dedent();
                        self.write("} else if ");
                    }
                    self.visit_expr(expr);
                },
                None => {
                    self.dedent();
                    self.write("} else");
                },
            }
            self.writeln(" {");
            self.handle(nodes);
        }
        self.handle_ws(ws);
        self.writeln("}");
    }

    fn write_loop(&mut self, ws1: &WS, var: &Target, iter: &Expr,
                  body: &'a [Node], ws2: &WS) {
        self.handle_ws(ws1);
        self.write("for (_loop_index, ");
        let targets = self.visit_target(var);
        for name in &targets {
            self.locals.insert(name.clone());
            self.write(name);
        }
        self.write(") in (&");
        self.visit_expr(iter);
        self.writeln(").into_iter().enumerate() {");

        self.handle(body);
        self.handle_ws(ws2);
        self.writeln("}");
        for name in &targets {
            self.locals.remove(name);
        }
    }

    fn write_block(&mut self, ws1: &WS, name: &str, ws2: &WS) {
        self.flush_ws(ws1);
        self.writeln(&format!("timpl.render_block_{}_to(writer);", name));
        self.prepare_ws(ws2);
    }

    fn write_block_def(&mut self, ws1: &WS, name: &str, nodes: &'a [Node],
                       ws2: &WS) {
        self.writeln("#[allow(unused_variables)]");
        self.writeln(&format!(
            "fn render_block_{}_to(&self, writer: &mut std::fmt::Write) {{",
            name));
        self.prepare_ws(ws1);
        self.handle(nodes);
        self.flush_ws(ws2);
        self.writeln("}");
    }

    fn handle(&mut self, nodes: &'a [Node]) {
        for n in nodes {
            match *n {
                Node::Lit(lws, val, rws) => { self.write_lit(lws, val, rws); }
                Node::Comment() => {},
                Node::Expr(ref ws, ref val) => { self.write_expr(ws, val); },
                Node::Cond(ref conds, ref ws) => {
                    self.write_cond(conds, ws);
                },
                Node::Loop(ref ws1, ref var, ref iter, ref body, ref ws2) => {
                    self.write_loop(ws1, var, iter, body, ws2);
                },
                Node::Block(ref ws1, name, ref ws2) => {
                    self.write_block(ws1, name, ws2);
                },
                Node::BlockDef(ref ws1, name, ref block_nodes, ref ws2) => {
                    self.write_block_def(ws1, name, block_nodes, ws2);
                }
                Node::Extends(_) => {
                    panic!("no extends or block definition allowed in content");
                },
            }
        }
    }

    fn write_header(&mut self, ast: &syn::DeriveInput,
                    trait_suffix: Option<&str>) {
        let mut anno = String::new();
        if ast.generics.lifetimes.len() > 0 {
            anno.push('<');
            for lt in &ast.generics.lifetimes {
                anno.push_str(lt.lifetime.ident.as_ref());
            }
            anno.push('>');
        };

        let name = if trait_suffix.is_some() {
            format!("TraitFrom{}", trait_suffix.unwrap())
        } else {
            "askama::Template".to_string()
        };
        self.writeln(&format!("impl{} {} for {}{} {{",
                              anno, &name, ast.ident.as_ref(), anno));
    }

    fn impl_template(&mut self, ast: &syn::DeriveInput, nodes: &'a [Node]) {
        self.write_header(ast, None);
        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.handle(nodes);
        self.flush_ws(&WS(false, false));
        self.writeln("}");
        self.writeln("}");
    }

    fn impl_trait(&mut self, ast: &syn::DeriveInput, base: &str,
                  blocks: &'a [Node], nodes: Option<&'a [Node]>) {
        self.write_header(ast, Some(&path_as_identifier(base)));
        self.handle(blocks);

        self.writeln("#[allow(unused_variables)]");
        let trait_name = format!("TraitFrom{}", path_as_identifier(base));
        self.writeln(&format!(
            "fn render_trait_to(&self, timpl: &{}, writer: &mut std::fmt::Write) {{",
            trait_name));

        if let Some(nodes) = nodes {
            self.handle(nodes);
            self.flush_ws(&WS(false, false));
        } else {
            self.writeln("self._parent.render_trait_to(self, writer);");
        }

        self.writeln("}");
        self.flush_ws(&WS(false, false));
        self.writeln("}");
    }

    fn impl_template_for_trait(&mut self, ast: &syn::DeriveInput, derived: bool) {
        self.write_header(ast, None);
        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        if derived {
            self.writeln("self._parent.render_trait_to(self, writer);");
        } else {
            self.writeln("self.render_trait_to(self, writer);");
        }
        self.writeln("}");
        self.writeln("}");
    }

    fn define_trait(&mut self, path: &str, block_names: &[&str]) {
        let trait_name = format!("TraitFrom{}", path_as_identifier(path));
        self.writeln(&format!("trait {} {{", &trait_name));

        for bname in block_names {
            self.writeln(&format!(
                "fn render_block_{}_to(&self, writer: &mut std::fmt::Write);",
                bname));
        }
        self.writeln(&format!(
            "fn render_trait_to(&self, timpl: &{}, writer: &mut std::fmt::Write);",
            trait_name));

        self.writeln("}");
    }

    fn result(self) -> String {
        self.buf
    }

}

pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> String {
    let mut base: Option<Expr> = None;
    let mut blocks = Vec::new();
    let mut block_names = Vec::new();
    let mut content = Vec::new();
    for n in nodes.drain(..) {
        match n {
            Node::Extends(path) => {
                match base {
                    Some(_) => panic!("multiple extend blocks found"),
                    None => { base = Some(path); },
                }
            },
            Node::BlockDef(ws1, name, _, ws2) => {
                blocks.push(n);
                block_names.push(name);
                content.push(Node::Block(ws1, name, ws2));
            },
            _ => { content.push(n); },
        }
    }

    let mut gen = Generator::new();
    if !blocks.is_empty() {
        if base.is_none() {
            gen.define_trait(path, &block_names);
        }
        let tmpl_path = match base {
            Some(Expr::StrLit(base_path)) => { base_path },
            _ => { path },
        };
        let trait_nodes = if base.is_none() { Some(&content[..]) } else { None };
        gen.impl_trait(ast, tmpl_path, &blocks, trait_nodes);
        gen.impl_template_for_trait(ast, base.is_some());
    } else {
        gen.impl_template(ast, &content);
    }
    gen.result()
}
<|endoftext|>


<commit_before>//! A variant of `SortedMap` that preserves insertion order.

use std::borrow::Borrow;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;

use crate::stable_hasher::{HashStable, StableHasher};
use rustc_index::vec::{Idx, IndexVec};

/// An indexed multi-map that preserves insertion order while permitting both *O*(log *n*) lookup of
/// an item by key and *O*(1) lookup by index.
///
/// This data structure is a hybrid of an [`IndexVec`] and a [`SortedMap`]. Like `IndexVec`,
/// `SortedIndexMultiMap` assigns a typed index to each item while preserving insertion order.
/// Like `SortedMap`, `SortedIndexMultiMap` has efficient lookup of items by key. However, this
/// is accomplished by sorting an array of item indices instead of the items themselves.
///
/// Unlike `SortedMap`, this data structure can hold multiple equivalent items at once, so the
/// `get_by_key` method and its variants return an iterator instead of an `Option`. Equivalent
/// items will be yielded in insertion order.
///
/// Unlike a general-purpose map like `BTreeSet` or `HashSet`, `SortedMap` and
/// `SortedIndexMultiMap` require *O*(*n*) time to insert a single item. This is because we may need
/// to insert into the middle of the sorted array. Users should avoid mutating this data structure
/// in-place.
///
/// [`SortedMap`]: super::SortedMap
#[derive(Clone, Debug)]
pub struct SortedIndexMultiMap<I: Idx, K, V> {
    /// The elements of the map in insertion order.
    items: IndexVec<I, (K, V)>,

    /// Indices of the items in the set, sorted by the item's key.
    idx_sorted_by_item_key: Vec<I>,
}

impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> {
    pub fn new() -> Self {
        SortedIndexMultiMap { items: IndexVec::new(), idx_sorted_by_item_key: Vec::new() }
    }

    pub fn len(&self) -> usize {
        self.items.len()
    }

    pub fn is_empty(&self) -> bool {
        self.items.is_empty()
    }

    /// Returns an iterator over the items in the map in insertion order.
    pub fn into_iter(self) -> impl DoubleEndedIterator<Item = (K, V)> {
        self.items.into_iter()
    }

    /// Returns an iterator over the items in the map in insertion order along with their indices.
    pub fn into_iter_enumerated(self) -> impl DoubleEndedIterator<Item = (I, (K, V))> {
        self.items.into_iter_enumerated()
    }

    /// Returns an iterator over the items in the map in insertion order.
    pub fn iter(&self) -> impl '_ + DoubleEndedIterator<Item = (&K, &V)> {
        self.items.iter().map(|(ref k, ref v)| (k, v))
    }

    /// Returns an iterator over the items in the map in insertion order along with their indices.
    pub fn iter_enumerated(&self) -> impl '_ + DoubleEndedIterator<Item = (I, (&K, &V))> {
        self.items.iter_enumerated().map(|(i, (ref k, ref v))| (i, (k, v)))
    }

    /// Returns the item in the map with the given index.
    pub fn get(&self, idx: I) -> Option<&(K, V)> {
        self.items.get(idx)
    }

    /// Returns an iterator over the items in the map that are equal to `key`.
    ///
    /// If there are multiple items that are equivalent to `key`, they will be yielded in
    /// insertion order.
    pub fn get_by_key<Q: 'a>(&'a self, key: &Q) -> impl 'a + Iterator<Item = &'a V>
    where
        Q: Ord + ?Sized,
        K: Borrow<Q>,
    {
        self.get_by_key_enumerated(key).map(|(_, v)| v)
    }

    /// Returns an iterator over the items in the map that are equal to `key` along with their
    /// indices.
    ///
    /// If there are multiple items that are equivalent to `key`, they will be yielded in
    /// insertion order.
    pub fn get_by_key_enumerated<Q>(&self, key: &Q) -> impl '_ + Iterator<Item = (I, &V)>
    where
        Q: Ord + ?Sized,
        K: Borrow<Q>,
    {
        // FIXME: This should be in the standard library as `equal_range`. See rust-lang/rfcs#2184.
        match self.binary_search_idx(key) {
            Err(_) => self.idxs_to_items_enumerated(&[]),

            Ok(idx) => {
                let start = self.find_lower_bound(key, idx);
                let end = self.find_upper_bound(key, idx);
                self.idxs_to_items_enumerated(&self.idx_sorted_by_item_key[start..end])
            }
        }
    }

    fn binary_search_idx<Q>(&self, key: &Q) -> Result<usize, usize>
    where
        Q: Ord + ?Sized,
        K: Borrow<Q>,
    {
        self.idx_sorted_by_item_key.binary_search_by(|&idx| self.items[idx].0.borrow().cmp(key))
    }

    /// Returns the index into the `idx_sorted_by_item_key` array of the first item equal to
    /// `key`.
    ///
    /// `initial` must be an index into that same array for an item that is equal to `key`.
    fn find_lower_bound<Q>(&self, key: &Q, initial: usize) -> usize
    where
        Q: Ord + ?Sized,
        K: Borrow<Q>,
    {
        debug_assert!(self.items[self.idx_sorted_by_item_key[initial]].0.borrow() == key);

        // FIXME: At present, this uses linear search, meaning lookup is only `O(log n)` if duplicate
        // entries are rare. It would be better to start with a linear search for the common case but
        // fall back to an exponential search if many duplicates are found. This applies to
        // `upper_bound` as well.
        let mut start = initial;
        while start != 0 && self.items[self.idx_sorted_by_item_key[start - 1]].0.borrow() == key {
            start -= 1;
        }

        start
    }

    /// Returns the index into the `idx_sorted_by_item_key` array of the first item greater than
    /// `key`, or `self.len()` if no such item exists.
    ///
    /// `initial` must be an index into that same array for an item that is equal to `key`.
    fn find_upper_bound<Q>(&self, key: &Q, initial: usize) -> usize
    where
        Q: Ord + ?Sized,
        K: Borrow<Q>,
    {
        debug_assert!(self.items[self.idx_sorted_by_item_key[initial]].0.borrow() == key);

        // See the FIXME for `find_lower_bound`.
        let mut end = initial + 1;
        let len = self.items.len();
        while end < len && self.items[self.idx_sorted_by_item_key[end]].0.borrow() == key {
            end += 1;
        }

        end
    }

    fn idxs_to_items_enumerated(&'a self, idxs: &'a [I]) -> impl 'a + Iterator<Item = (I, &'a V)> {
        idxs.iter().map(move |&idx| (idx, &self.items[idx].1))
    }
}

impl<I: Idx, K: Eq, V: Eq> Eq for SortedIndexMultiMap<I, K, V> {}
impl<I: Idx, K: PartialEq, V: PartialEq> PartialEq for SortedIndexMultiMap<I, K, V> {
    fn eq(&self, other: &Self) -> bool {
        // No need to compare the sorted index. If the items are the same, the index will be too.
        self.items == other.items
    }
}

impl<I: Idx, K, V> Hash for SortedIndexMultiMap<I, K, V>
where
    K: Hash,
    V: Hash,
{
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.items.hash(hasher)
    }
}
impl<I: Idx, K, V, C> HashStable<C> for SortedIndexMultiMap<I, K, V>
where
    K: HashStable<C>,
    V: HashStable<C>,
{
    fn hash_stable(&self, ctx: &mut C, hasher: &mut StableHasher) {
        self.items.hash_stable(ctx, hasher)
    }
}

impl<I: Idx, K: Ord, V> FromIterator<(K, V)> for SortedIndexMultiMap<I, K, V> {
    fn from_iter<J>(iter: J) -> Self
    where
        J: IntoIterator<Item = (K, V)>,
    {
        let items = IndexVec::from_iter(iter);
        let mut idx_sorted_by_item_key: Vec<_> = items.indices().collect();

        // `sort_by_key` is stable, so insertion order is preserved for duplicate items.
        idx_sorted_by_item_key.sort_by_key(|&idx| &items[idx].0);

        SortedIndexMultiMap { items, idx_sorted_by_item_key }
    }
}

impl<I: Idx, K, V> std::ops::Index<I> for SortedIndexMultiMap<I, K, V> {
    type Output = V;

    fn index(&self, idx: I) -> &Self::Output {
        &self.items[idx].1
    }
}

#[cfg(tests)]
mod tests;
<commit_msg>Auto merge of #86392 - JohnTitor:use-partition-point, r=petrochenkov<commit_after>//! A variant of `SortedMap` that preserves insertion order.

use std::borrow::Borrow;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;

use crate::stable_hasher::{HashStable, StableHasher};
use rustc_index::vec::{Idx, IndexVec};

/// An indexed multi-map that preserves insertion order while permitting both *O*(log *n*) lookup of
/// an item by key and *O*(1) lookup by index.
///
/// This data structure is a hybrid of an [`IndexVec`] and a [`SortedMap`]. Like `IndexVec`,
/// `SortedIndexMultiMap` assigns a typed index to each item while preserving insertion order.
/// Like `SortedMap`, `SortedIndexMultiMap` has efficient lookup of items by key. However, this
/// is accomplished by sorting an array of item indices instead of the items themselves.
///
/// Unlike `SortedMap`, this data structure can hold multiple equivalent items at once, so the
/// `get_by_key` method and its variants return an iterator instead of an `Option`. Equivalent
/// items will be yielded in insertion order.
///
/// Unlike a general-purpose map like `BTreeSet` or `HashSet`, `SortedMap` and
/// `SortedIndexMultiMap` require *O*(*n*) time to insert a single item. This is because we may need
/// to insert into the middle of the sorted array. Users should avoid mutating this data structure
/// in-place.
///
/// [`SortedMap`]: super::SortedMap
#[derive(Clone, Debug)]
pub struct SortedIndexMultiMap<I: Idx, K, V> {
    /// The elements of the map in insertion order.
    items: IndexVec<I, (K, V)>,

    /// Indices of the items in the set, sorted by the item's key.
    idx_sorted_by_item_key: Vec<I>,
}

impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> {
    pub fn new() -> Self {
        SortedIndexMultiMap { items: IndexVec::new(), idx_sorted_by_item_key: Vec::new() }
    }

    pub fn len(&self) -> usize {
        self.items.len()
    }

    pub fn is_empty(&self) -> bool {
        self.items.is_empty()
    }

    /// Returns an iterator over the items in the map in insertion order.
    pub fn into_iter(self) -> impl DoubleEndedIterator<Item = (K, V)> {
        self.items.into_iter()
    }

    /// Returns an iterator over the items in the map in insertion order along with their indices.
    pub fn into_iter_enumerated(self) -> impl DoubleEndedIterator<Item = (I, (K, V))> {
        self.items.into_iter_enumerated()
    }

    /// Returns an iterator over the items in the map in insertion order.
    pub fn iter(&self) -> impl '_ + DoubleEndedIterator<Item = (&K, &V)> {
        self.items.iter().map(|(ref k, ref v)| (k, v))
    }

    /// Returns an iterator over the items in the map in insertion order along with their indices.
    pub fn iter_enumerated(&self) -> impl '_ + DoubleEndedIterator<Item = (I, (&K, &V))> {
        self.items.iter_enumerated().map(|(i, (ref k, ref v))| (i, (k, v)))
    }

    /// Returns the item in the map with the given index.
    pub fn get(&self, idx: I) -> Option<&(K, V)> {
        self.items.get(idx)
    }

    /// Returns an iterator over the items in the map that are equal to `key`.
    ///
    /// If there are multiple items that are equivalent to `key`, they will be yielded in
    /// insertion order.
    pub fn get_by_key<Q: 'a>(&'a self, key: &Q) -> impl 'a + Iterator<Item = &'a V>
    where
        Q: Ord + ?Sized,
        K: Borrow<Q>,
    {
        self.get_by_key_enumerated(key).map(|(_, v)| v)
    }

    /// Returns an iterator over the items in the map that are equal to `key` along with their
    /// indices.
    ///
    /// If there are multiple items that are equivalent to `key`, they will be yielded in
    /// insertion order.
    pub fn get_by_key_enumerated<Q>(&self, key: &Q) -> impl '_ + Iterator<Item = (I, &V)>
    where
        Q: Ord + ?Sized,
        K: Borrow<Q>,
    {
        match self.binary_search_idx(key) {
            Err(_) => self.idxs_to_items_enumerated(&[]),

            Ok(idx) => {
                let start = self.idx_sorted_by_item_key[..idx]
                    .partition_point(|&i| self.items[i].0.borrow() != key);
                let end = idx
                    + self.idx_sorted_by_item_key[idx..]
                        .partition_point(|&i| self.items[i].0.borrow() == key);
                self.idxs_to_items_enumerated(&self.idx_sorted_by_item_key[start..end])
            }
        }
    }

    fn binary_search_idx<Q>(&self, key: &Q) -> Result<usize, usize>
    where
        Q: Ord + ?Sized,
        K: Borrow<Q>,
    {
        self.idx_sorted_by_item_key.binary_search_by(|&idx| self.items[idx].0.borrow().cmp(key))
    }

    fn idxs_to_items_enumerated(&'a self, idxs: &'a [I]) -> impl 'a + Iterator<Item = (I, &'a V)> {
        idxs.iter().map(move |&idx| (idx, &self.items[idx].1))
    }
}

impl<I: Idx, K: Eq, V: Eq> Eq for SortedIndexMultiMap<I, K, V> {}
impl<I: Idx, K: PartialEq, V: PartialEq> PartialEq for SortedIndexMultiMap<I, K, V> {
    fn eq(&self, other: &Self) -> bool {
        // No need to compare the sorted index. If the items are the same, the index will be too.
        self.items == other.items
    }
}

impl<I: Idx, K, V> Hash for SortedIndexMultiMap<I, K, V>
where
    K: Hash,
    V: Hash,
{
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.items.hash(hasher)
    }
}
impl<I: Idx, K, V, C> HashStable<C> for SortedIndexMultiMap<I, K, V>
where
    K: HashStable<C>,
    V: HashStable<C>,
{
    fn hash_stable(&self, ctx: &mut C, hasher: &mut StableHasher) {
        self.items.hash_stable(ctx, hasher)
    }
}

impl<I: Idx, K: Ord, V> FromIterator<(K, V)> for SortedIndexMultiMap<I, K, V> {
    fn from_iter<J>(iter: J) -> Self
    where
        J: IntoIterator<Item = (K, V)>,
    {
        let items = IndexVec::from_iter(iter);
        let mut idx_sorted_by_item_key: Vec<_> = items.indices().collect();

        // `sort_by_key` is stable, so insertion order is preserved for duplicate items.
        idx_sorted_by_item_key.sort_by_key(|&idx| &items[idx].0);

        SortedIndexMultiMap { items, idx_sorted_by_item_key }
    }
}

impl<I: Idx, K, V> std::ops::Index<I> for SortedIndexMultiMap<I, K, V> {
    type Output = V;

    fn index(&self, idx: I) -> &Self::Output {
        &self.items[idx].1
    }
}

#[cfg(tests)]
mod tests;
<|endoftext|>


<commit_before>#![feature(generator_trait)]
#![no_std]

pub use core::*;

pub mod future {
    pub use core::future::Future;
    use core::ops::Generator;
    use core::pin::Pin;
    use core::task::Poll;

    pub fn poll_with_tls_context<F>(f: Pin<&mut F>) -> Poll<F::Output>
    where
        F: Future,
    {
        crate::executor::poll(f)
    }

    pub fn from_generator<G: Generator<Yield = ()>>(
        generator: G,
    ) -> impl Future<Output = G::Return> {
        crate::executor::from_generator(generator)
    }
}

pub mod executor {
    use core::future::Future;
    use core::ops::Generator;
    use core::ops::GeneratorState;
    use core::pin::Pin;
    use core::ptr;
    use core::task::Context;
    use core::task::Poll;
    use core::task::RawWaker;
    use core::task::RawWakerVTable;
    use core::task::Waker;

    static DUMMY_WAKER_VTABLE: RawWakerVTable =
        RawWakerVTable::new(clone, do_nothing, do_nothing, do_nothing);

    extern "Rust" {
        #[link_name = "libtock::syscalls::yieldk"]
        fn yieldk();
    }

    pub fn block_on<T>(mut future: impl Future<Output = T>) -> T {
        let waker = unsafe { Waker::from_raw(get_dummy_waker()) };
        let mut context = Context::from_waker(&waker);

        loop {
            let pinned_future = unsafe { Pin::new_unchecked(&mut future) };
            let result = pinned_future.poll(&mut context);
            match result {
                Poll::Pending => unsafe { yieldk() },
                Poll::Ready(value) => {
                    return value;
                }
            }
        }
    }

    pub(crate) fn poll<F: Future>(pinned_future: Pin<&mut F>) -> Poll<F::Output> {
        let waker = unsafe { Waker::from_raw(get_dummy_waker()) };
        let mut context = Context::from_waker(&waker);
        pinned_future.poll(&mut context)
    }

    pub(crate) fn from_generator<G: Generator<Yield = ()>>(
        generator: G,
    ) -> impl Future<Output = G::Return> {
        GeneratorFuture { generator }
    }

    struct GeneratorFuture<G> {
        generator: G,
    }

    impl<G: Generator<Yield = ()>> Future for GeneratorFuture<G> {
        type Output = G::Return;

        fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
            let pin = unsafe { Pin::new_unchecked(&mut Pin::into_inner_unchecked(self).generator) };
            match pin.resume() {
                GeneratorState::Yielded(()) => Poll::Pending,
                GeneratorState::Complete(out) => Poll::Ready(out),
            }
        }
    }

    fn clone(_x: *const ()) -> RawWaker {
        get_dummy_waker()
    }

    fn get_dummy_waker() -> RawWaker {
        RawWaker::new(ptr::null(), &DUMMY_WAKER_VTABLE)
    }

    fn do_nothing(_x: *const ()) {}
}
<commit_msg>Improve understandability of async-support<commit_after>#![feature(generator_trait)]
#![no_std]

pub use core::*;

pub mod future {
    pub use core::future::Future;
    use core::ops::Generator;
    use core::pin::Pin;
    use core::task::Poll;

    pub fn poll_with_tls_context<F>(f: Pin<&mut F>) -> Poll<F::Output>
    where
        F: Future,
    {
        crate::executor::poll(f)
    }

    pub fn from_generator<G: Generator<Yield = ()>>(
        generator: G,
    ) -> impl Future<Output = G::Return> {
        crate::executor::from_generator(generator)
    }
}

pub mod executor {
    use core::future::Future;
    use core::ops::Generator;
    use core::ops::GeneratorState;
    use core::pin::Pin;
    use core::ptr;
    use core::task::Context;
    use core::task::Poll;
    use core::task::RawWaker;
    use core::task::RawWakerVTable;
    use core::task::Waker;

    extern "Rust" {
        #[link_name = "libtock::syscalls::yieldk"]
        fn yieldk();
    }

    pub fn block_on<T>(mut future: impl Future<Output = T>) -> T {
        // Contract described in the Rustdoc: "A value, once pinned, must remain pinned forever (...).".
        // IOW calling Pin::new_unchecked is safe as long as no &mut future is leaked after pinning.
        let mut pinned_future = unsafe { Pin::new_unchecked(&mut future) };

        loop {
            match poll(pinned_future.as_mut()) {
                Poll::Pending => unsafe { yieldk() },
                Poll::Ready(value) => {
                    return value;
                }
            }
        }
    }

    pub(crate) fn poll<F: Future>(pinned_future: Pin<&mut F>) -> Poll<F::Output> {
        let waker = unsafe { Waker::from_raw(get_dummy_waker()) };
        let mut context = Context::from_waker(&waker);
        pinned_future.poll(&mut context)
    }

    // Since Tock OS comes with waking-up functionality built-in, we use dummy wakers that do nothing at all.
    fn get_dummy_waker() -> RawWaker {
        fn clone(_x: *const ()) -> RawWaker {
            get_dummy_waker()
        }

        fn do_nothing(_x: *const ()) {}

        // This vtable implements the methods required for managing the lifecycle of the wakers.
        // Our wakers are dummies, so those functions don't do anything.
        static DUMMY_WAKER_VTABLE: RawWakerVTable =
            RawWakerVTable::new(clone, do_nothing, do_nothing, do_nothing);

        // The wakers don't have any implementation, so the instance can simply be null.
        RawWaker::new(ptr::null(), &DUMMY_WAKER_VTABLE)
    }

    pub(crate) fn from_generator<G: Generator<Yield = ()>>(
        generator: G,
    ) -> impl Future<Output = G::Return> {
        GeneratorFuture { generator }
    }

    struct GeneratorFuture<G> {
        generator: G,
    }

    impl<G: Generator<Yield = ()>> Future for GeneratorFuture<G> {
        type Output = G::Return;

        fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
            // Pin::map_unchecked_mut is safe as long as the move and drop guarantees are propagated through the mapping.
            // This is trivially satisfied since our future is only a newtype decorator of the generator.
            let pinned_generator =
                unsafe { self.map_unchecked_mut(|future| &mut future.generator) };

            match pinned_generator.resume() {
                GeneratorState::Yielded(()) => Poll::Pending,
                GeneratorState::Complete(out) => Poll::Ready(out),
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::path::Path;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => panic!("An error occured during package finding.", why),
    });
}

#[derive(Serialize, Deserialize)]
struct Package {
    name: String,
    version: String,
    crc32: String,
    dependencies: Vec<Package>
}

#[derive(Serialize, Deserialize)]
struct PackageList {
    packages: Vec<Package>,
    last_updated: Date
}

fn find_package(name: &str, path:&Path) -> Result<String, &str>
{
    let mut list = custom_try!(match File::open(path));
    let mut reader = BufReader::new(list);
    let mut buffer = reader.read_to_string();
    let packages: PackageList = custom_try!(serde_json::from_str(buffer));
}<commit_msg>(Perhaps) completing finding package functionality<commit_after>use std::error::Error;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::path::Path;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => panic!("An error occured during package finding.", why),
    });
}

#[derive(Serialize, Deserialize)]
struct Package {
    name: String,
    version: String,
    crc32: String,
    url: String,
    dependencies: Vec<Package>
}

#[derive(Serialize, Deserialize)]
struct PackageList {
    packages: Vec<Package>,
    last_updated: Date
}

fn find_package(name: &str, path:&Path) -> Result<Vec<Package>, &str>
{
    let mut list = custom_try!(match File::open(path));
    let mut reader = BufReader::new(list);
    let mut buffer = reader.read_to_string();
    let package_list: PackageList = custom_try!(serde_json::from_str(buffer));

    let filtered = package_list.packages.into_iter()
                    .filter(|x| !x.name.contains(name))
                    .collect::<Vec<_>>();

    match filtered.len() {
        0 => Err("Package not found"),
        _ => Ok(filtered)
    }
}

<|endoftext|>


<commit_before>//! # The Redox Library
//!
//! The Redox Library contains a collection of commonly used low-level software
//! constructs to be used on top of the base operating system, including graphics
//! support and windowing, a basic filesystem, audio support, a simple console
//! with shell style functions, an event system, and environment argument support.

#![crate_type="rlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(allow_internal_unstable)]
#![feature(asm)]
#![feature(associated_consts)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(collections_bound)]
#![feature(core)]
#![feature(core_intrinsics)]
#![feature(core_panic)]
#![feature(core_simd)]
#![feature(int_error_internals)]
#![feature(lang_items)]
#![feature(macro_reexport)]
#![feature(rand)]
#![feature(raw)]
#![feature(reflect_marker)]
#![feature(slice_concat_ext)]
#![feature(unicode)]
#![feature(unsafe_no_drop_flag)]
#![feature(box_patterns)]
#![feature(vec_push_all)]
#![feature(wrapping)]
#![feature(zero_one)]
#![feature(no_std)]
#![no_std]

//#![warn(missing_docs)]

/* STD COPY { */
    // We want to reexport a few macros from core but libcore has already been
    // imported by the compiler (via our #[no_std] attribute) In this case we just
    // add a new crate name so we can attach the reexports to it.
    #[macro_reexport(assert, assert_eq, debug_assert, debug_assert_eq,
                    unreachable, unimplemented, write, writeln)]
    extern crate core as __core;

    #[macro_use]
    #[macro_reexport(vec, format)]
    extern crate collections as core_collections;

    #[allow(deprecated)] extern crate rand as core_rand;
    extern crate alloc;
    extern crate rustc_unicode;
    //TODO extern crate libc;

    // NB: These reexports are in the order they should be listed in rustdoc

    pub use core::any;
    pub use core::cell;
    pub use core::clone;
    pub use core::cmp;
    pub use core::convert;
    pub use core::default;
    pub use core::hash;
    pub use core::intrinsics;
    pub use core::iter;
    pub use core::marker;
    pub use core::mem;
    pub use core::ops;
    pub use core::ptr;
    pub use core::raw;
    #[allow(deprecated)]
    pub use core::simd;
    pub use core::result;
    pub use core::option;
    pub mod error;

    pub use alloc::arc;
    pub use alloc::boxed;
    pub use alloc::rc;

    pub use core_collections::borrow;
    pub use core_collections::fmt;
    pub use core_collections::slice;
    pub use core_collections::str;
    pub use core_collections::string;
    pub use core_collections::vec;

    pub use rustc_unicode::char;

    /* Exported macros */

    #[macro_use]
    pub mod macros;

    // TODO mod rtdeps;

    /* The Prelude. */
    pub mod prelude;

    /* Primitive types */

    // NB: slice and str are primitive types too, but their module docs + primitive
    // doc pages are inlined from the public re-exports of core_collections::{slice,
    // str} above.

    pub use core::isize;
    pub use core::i8;
    pub use core::i16;
    pub use core::i32;
    pub use core::i64;

    pub use core::usize;
    pub use core::u8;
    pub use core::u16;
    pub use core::u32;
    pub use core::u64;

    // TODO: Add methods to f64
    pub use core::num;

    //TODO #[path = "num/f32.rs"]   pub mod f32;
    //TODO #[path = "num/f64.rs"]   pub mod f64;

    pub mod ascii;

    /* Common traits */

    pub mod floating_num;

    /* Runtime and platform support */

    #[macro_use]
    pub mod thread;

    pub mod collections;
    // TODO pub mod dynamic_lib;
    pub mod env;
    // TODO pub mod ffi;
    pub mod fs;
    pub mod io;
    pub mod net;
    // TODO pub mod os;
    // TODO pub mod path;
    pub mod process;
    pub mod sync;
    pub mod time;

    //TODO #[macro_use]
    //TODO #[path = "sys/common/mod.rs"] mod sys_common;

    //TODO #[cfg(unix)]
    //TODO #[path = "sys/unix/mod.rs"] mod sys;
    //TODO #[cfg(windows)]
    //TODO #[path = "sys/windows/mod.rs"] mod sys;

    pub mod rt;
    //TODO mod panicking;
    pub use __core::panicking;

    pub mod rand_old;
    pub mod hashmap;

    // Some external utilities of the standard library rely on randomness (aka
    // rustc_back::TempDir and tests) and need a way to get at the OS rng we've got
    // here. This module is not at all intended for stabilization as-is, however,
    // but it may be stabilized long-term. As a result we're exposing a hidden,
    // unstable module so we can get our build working.
    #[doc(hidden)]
    //TODO #[unstable(feature = "rand", issue = "0")]
    pub mod rand {
        pub use core_rand::{/*thread_rng, ThreadRng,*/ Rng};
    }
/* } STD COPY */

/* Additional Stuff { */
    pub use boxed::Box;
    pub use env::*;
    pub use fs::*;
    pub use io::*;
    pub use rand_old::*;
    pub use string::*;
    pub use vec::Vec;

    pub use url::*;
    pub use get_slice::*;
    pub use to_num::*;

    pub mod alloc_system;

    /// A module for necessary C and assembly constructs
    #[path="../../kernel/externs.rs"]
    pub mod externs;

    pub mod start;

    /// A module for system calls
    pub mod syscall;

    /// A module for audio
    pub mod audio;

    pub mod panic;

    pub mod url;

    pub mod get_slice;
    pub mod to_num;
/* } Additional Stuff */
<commit_msg>Add prelude<commit_after>//! # The Redox Library
//!
//! The Redox Library contains a collection of commonly used low-level software
//! constructs to be used on top of the base operating system, including graphics
//! support and windowing, a basic filesystem, audio support, a simple console
//! with shell style functions, an event system, and environment argument support.

#![crate_type="rlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(allow_internal_unstable)]
#![feature(asm)]
#![feature(associated_consts)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(collections_bound)]
#![feature(core)]
#![feature(core_intrinsics)]
#![feature(core_panic)]
#![feature(core_simd)]
#![feature(int_error_internals)]
#![feature(lang_items)]
#![feature(macro_reexport)]
#![feature(rand)]
#![feature(raw)]
#![feature(reflect_marker)]
#![feature(slice_concat_ext)]
#![feature(unicode)]
#![feature(unsafe_no_drop_flag)]
#![feature(box_patterns)]
#![feature(vec_push_all)]
#![feature(wrapping)]
#![feature(zero_one)]
#![feature(no_std)]
#![feature(prelude_import)]
#![no_std]

//#![warn(missing_docs)]

/* STD COPY { */
    // We want to reexport a few macros from core but libcore has already been
    // imported by the compiler (via our #[no_std] attribute) In this case we just
    // add a new crate name so we can attach the reexports to it.
    #[macro_reexport(assert, assert_eq, debug_assert, debug_assert_eq,
                    unreachable, unimplemented, write, writeln)]
    extern crate core as __core;

    #[macro_use]
    #[macro_reexport(vec, format)]
    extern crate collections as core_collections;

    #[allow(deprecated)] extern crate rand as core_rand;
    extern crate alloc;
    extern crate rustc_unicode;
    //TODO extern crate libc;

    // NB: These reexports are in the order they should be listed in rustdoc

    pub use core::any;
    pub use core::cell;
    pub use core::clone;
    pub use core::cmp;
    pub use core::convert;
    pub use core::default;
    pub use core::hash;
    pub use core::intrinsics;
    pub use core::iter;
    pub use core::marker;
    pub use core::mem;
    pub use core::ops;
    pub use core::ptr;
    pub use core::raw;
    #[allow(deprecated)]
    pub use core::simd;
    pub use core::result;
    pub use core::option;
    pub mod error;

    pub use alloc::arc;
    pub use alloc::boxed;
    pub use alloc::rc;

    pub use core_collections::borrow;
    pub use core_collections::fmt;
    pub use core_collections::slice;
    pub use core_collections::str;
    pub use core_collections::string;
    pub use core_collections::vec;

    pub use rustc_unicode::char;

    /* Exported macros */

    #[macro_use]
    pub mod macros;

    // TODO mod rtdeps;

    /* The Prelude. */
    #[prelude_import]
    pub mod prelude;

    /* Primitive types */

    // NB: slice and str are primitive types too, but their module docs + primitive
    // doc pages are inlined from the public re-exports of core_collections::{slice,
    // str} above.

    pub use core::isize;
    pub use core::i8;
    pub use core::i16;
    pub use core::i32;
    pub use core::i64;

    pub use core::usize;
    pub use core::u8;
    pub use core::u16;
    pub use core::u32;
    pub use core::u64;

    // TODO: Add methods to f64
    pub use core::num;

    //TODO #[path = "num/f32.rs"]   pub mod f32;
    //TODO #[path = "num/f64.rs"]   pub mod f64;

    pub mod ascii;

    /* Common traits */

    pub mod floating_num;

    /* Runtime and platform support */

    #[macro_use]
    pub mod thread;

    pub mod collections;
    // TODO pub mod dynamic_lib;
    pub mod env;
    // TODO pub mod ffi;
    pub mod fs;
    pub mod io;
    pub mod net;
    // TODO pub mod os;
    // TODO pub mod path;
    pub mod process;
    pub mod sync;
    pub mod time;

    //TODO #[macro_use]
    //TODO #[path = "sys/common/mod.rs"] mod sys_common;

    //TODO #[cfg(unix)]
    //TODO #[path = "sys/unix/mod.rs"] mod sys;
    //TODO #[cfg(windows)]
    //TODO #[path = "sys/windows/mod.rs"] mod sys;

    pub mod rt;
    //TODO mod panicking;
    pub use __core::panicking;

    pub mod rand_old;
    pub mod hashmap;

    // Some external utilities of the standard library rely on randomness (aka
    // rustc_back::TempDir and tests) and need a way to get at the OS rng we've got
    // here. This module is not at all intended for stabilization as-is, however,
    // but it may be stabilized long-term. As a result we're exposing a hidden,
    // unstable module so we can get our build working.
    #[doc(hidden)]
    //TODO #[unstable(feature = "rand", issue = "0")]
    pub mod rand {
        pub use core_rand::{/*thread_rng, ThreadRng,*/ Rng};
    }
/* } STD COPY */

/* Additional Stuff { */
    pub use boxed::Box;
    pub use env::*;
    pub use fs::*;
    pub use io::*;
    pub use rand_old::*;
    pub use string::*;
    pub use vec::Vec;

    pub use url::*;
    pub use get_slice::*;
    pub use to_num::*;

    pub mod alloc_system;

    /// A module for necessary C and assembly constructs
    #[path="../../kernel/externs.rs"]
    pub mod externs;

    pub mod start;

    /// A module for system calls
    pub mod syscall;

    /// A module for audio
    pub mod audio;

    pub mod panic;

    pub mod url;

    pub mod get_slice;
    pub mod to_num;
/* } Additional Stuff */
<|endoftext|>


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

//! This module is the main module for the Ligature project.
//! It represents to common types and traits used by Ligature.

#![deny(missing_docs)]
//#![deny(missing_doc_example)] <-- for later, when I'm swole

#[macro_use]
extern crate lazy_static;

use regex::Regex;
use serde::{Deserialize, Serialize};

/// A string that represents a Dataset by name.
/// Currently can only be ASCII text separated by /
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
pub struct Dataset(String);

impl Dataset {
    /// Creates a new Dataset and returns a Result based on if it is valid or not.
    pub fn new(name: &str) -> Result<Dataset, LigatureError> {
        lazy_static! {
            static ref RE: Regex =
                Regex::new(r"^([a-zA-Z_]{1}[a-zA-Z0-9_]*)(/[a-zA-Z_]{1}[a-zA-Z0-9_]*)*$").unwrap();
        }

        if RE.is_match(name) {
            Ok(Dataset(name.to_string()))
        } else {
            Err(LigatureError(format!("Invalid Dataset name {}", name)))
        }
    }

    /// Returns the name of the given Dataset.
    pub fn name(&self) -> &str {
        &self.0
    }
}

/// An Entity that is identified by a unique u64 id.
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub struct Entity(pub u64);

/// A named connection between an Entity and a Value.
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub struct Attribute(String);

impl Attribute {
    /// Creates a new Arrow and returns a Result based on if it is valid or not.
    pub fn new(name: &str) -> Result<Self, LigatureError> {
        lazy_static! {
            static ref RE: Regex = Regex::new(r"^[a-zA-Z_]{1}[a-zA-Z0-9_]*$").unwrap();
        }

        if RE.is_match(name) {
            Ok(Self(name.to_string()))
        } else {
            Err(LigatureError(format!("Invalid Attribute name {}", name)))
        }
    }

    /// Returns the name of the given Arrow.
    pub fn name(&self) -> &str {
        &self.0
    }
}

/// An enum that represents all the currently supported Value types.
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub enum Value {
    /// An Entity.
    Entity(Entity),
    /// A String used for a Ligature literal
    StringLiteral(String),
    /// An i64 used for a Ligature literal
    IntegerLiteral(i64),
    /// An f64 used for a Ligature literal
    FloatLiteral(f64),
}

/// A set of enums used to express range queries when it makes sense for that type (ie no support for BooleanLiteralRange or UnknownLiteralRange since they don't make sense).
#[derive(Debug)]
pub enum Range {
    /// Represents a String range using basic String comparisons.
    StringLiteralRange {
        /// The starting String (inclusive)
        start: String,
        /// The end String (exclusive)
        end: String,
    },
    /// Represents a String range using basic i64 comparisons.
    IntegerLiteralRange {
        /// The starting i64 (inclusive)
        start: i64,
        /// The end i64 (exclusive)
        end: i64,
    },
    /// Represents a String range using basic f64 comparisons.
    FloatLiteralRange {
        /// The starting f64 (inclusive)
        start: f64,
        /// The end f64 (exclusive)
        end: f64,
    },
}

/// A Statement is a grouping of an Entity, an Attribute, and a Value.
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct Statement {
    /// The Entity of a Statement
    pub entity: Entity,
    /// The Attribute of a Statement
    pub attribute: Attribute,
    /// The Value of a Statement
    pub value: Value,
}

/// A Statement that has been persisted so it has an associated Context Entity.
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct PersistedStatement {
    /// The target Statment
    pub statement: Statement,
    /// The Context of this Statement
    pub context: Entity,
}

/// A general struct for representing errors involving Ligature.
/// TODO should probably be an enum with a bunch of specific cases
#[derive(Debug, PartialEq, Eq)]
pub struct LigatureError(pub String);

/// A trait that all Ligature implementations implement.
pub trait Ligature {
    /// Returns all Datasets in a Ligature instance.
    fn all_datasets(&self) -> Box<dyn Iterator<Item = Result<Dataset, LigatureError>>>;

    /// Check if a given Dataset exists.
    fn dataset_exists(&self, dataset: &Dataset) -> Result<bool, LigatureError>;

    /// Returns all Datasets in a Ligature instance that start with the given prefix.
    fn match_datasets_prefix(
        &self,
        prefix: &str,
    ) -> Box<dyn Iterator<Item = Result<Dataset, LigatureError>>>;

    /// Returns all Datasets in a Ligature instance that are in a given range (inclusive, exclusive].
    fn match_datasets_range(
        &self,
        start: &str,
        end: &str,
    ) -> Box<dyn Iterator<Item = Result<Dataset, LigatureError>>>;

    /// Creates a dataset with the given name.
    /// TODO should probably return its own error type { InvalidDataset, DatasetExists, CouldNotCreateDataset }
    fn create_dataset(&self, dataset: &Dataset) -> Result<(), LigatureError>;

    /// Deletes a dataset with the given name.
    /// TODO should probably return its own error type { InvalidDataset, CouldNotDeleteDataset }
    fn delete_dataset(&self, dataset: &Dataset) -> Result<(), LigatureError>;

    /// Initiazes a QueryTx
    /// TODO should probably return its own error type CouldNotInitializeQueryTx
    fn query<T>(&self, dataset: &Dataset, f: QueryFn<T>) -> Result<T, LigatureError>;

    /// Initiazes a WriteTx
    /// TODO should probably return its own error type CouldNotInitializeWriteTx
    fn write<T>(&self, dataset: &Dataset, f: WriteFn<T>) -> Result<T, LigatureError>;
}

/// An Fn that is used when making a Query tranaction.
pub type QueryFn<T> = Box<dyn Fn(Box<&dyn QueryTx>) -> Result<T, LigatureError>>;

/// An Fn that is used when making a Write transaction.
pub type WriteFn<T> = Box<dyn Fn(Box<&dyn WriteTx>) -> Result<T, LigatureError>>;

/// Represents a QueryTx within the context of a Ligature instance and a single Dataset
pub trait QueryTx {
    /// Returns all PersistedStatements in this Dataset.
    fn all_statements(
        &self,
    ) -> Box<dyn Iterator<Item = Result<PersistedStatement, LigatureError>> + '_>;

    /// Returns all PersistedStatements that match the given criteria.
    /// If a parameter is None then it matches all, so passing all Nones is the same as calling all_statements.
    fn match_statements(
        &self,
        source: Option<Entity>,
        arrow: Option<Attribute>,
        target: Option<Value>,
    ) -> Box<dyn Iterator<Item = Result<PersistedStatement, LigatureError>> + '_>;

    /// Retuns all PersistedStatements that match the given criteria.
    /// If a parameter is None then it matches all.
    fn match_statements_range(
        &self,
        source: Option<Entity>,
        arrow: Option<Attribute>,
        target: Range,
    ) -> Box<dyn Iterator<Item = Result<PersistedStatement, LigatureError>> + '_>;

    /// Returns the PersistedStatement for the given context.
    fn statement_for_context(
        &self,
        context: &Entity,
    ) -> Result<Option<PersistedStatement>, LigatureError>;
}

/// Represents a WriteTx within the context of a Ligature instance and a single Dataset
pub trait WriteTx {
    /// Creates a new, unique Entity within this Dataset.
    /// Note: Entitys are shared across named graphs in a given Dataset.
    fn new_entity(&self) -> Result<Entity, LigatureError>;

    /// Adds a given Statement to this Dataset.
    /// If the Statement already exists nothing happens (TODO maybe add it with a new context?).
    /// Note: Potentally could trigger a ValidationError
    fn add_statement(&self, statement: &Statement) -> Result<PersistedStatement, LigatureError>;

    /// Removes a given PersistedStatement from this Dataset.
    /// If the PersistedStatement doesn't exist nothing happens and returns Ok(false).
    /// This function returns Ok(true) only if the given PersistedStatement was found and removed.
    /// Note: Potentally could trigger a ValidationError.
    fn remove_statement(
        &self,
        persisted_statement: &PersistedStatement,
    ) -> Result<bool, LigatureError>;

    /// Cancels this transaction so that none of the changes made so far will be stored.
    /// This also closes this transaction so no other methods can be called without returning a LigatureError.
    fn cancel(&self) -> Result<(), LigatureError>;
}
<commit_msg>removing PersistedStatement, closes #182<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! This module is the main module for the Ligature project.
//! It represents to common types and traits used by Ligature.

#![deny(missing_docs)]
//#![deny(missing_doc_example)] <-- for later, when I'm swole

#[macro_use]
extern crate lazy_static;

use regex::Regex;
use serde::{Deserialize, Serialize};

/// A string that represents a Dataset by name.
/// Currently can only be ASCII text separated by /
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
pub struct Dataset(String);

impl Dataset {
    /// Creates a new Dataset and returns a Result based on if it is valid or not.
    pub fn new(name: &str) -> Result<Dataset, LigatureError> {
        lazy_static! {
            static ref RE: Regex =
                Regex::new(r"^([a-zA-Z_]{1}[a-zA-Z0-9_]*)(/[a-zA-Z_]{1}[a-zA-Z0-9_]*)*$").unwrap();
        }

        if RE.is_match(name) {
            Ok(Dataset(name.to_string()))
        } else {
            Err(LigatureError(format!("Invalid Dataset name {}", name)))
        }
    }

    /// Returns the name of the given Dataset.
    pub fn name(&self) -> &str {
        &self.0
    }
}

/// An Entity that is identified by a unique u64 id.
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub struct Entity(pub u64);

/// A named connection between an Entity and a Value.
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub struct Attribute(String);

impl Attribute {
    /// Creates a new Arrow and returns a Result based on if it is valid or not.
    pub fn new(name: &str) -> Result<Self, LigatureError> {
        lazy_static! {
            static ref RE: Regex = Regex::new(r"^[a-zA-Z_]{1}[a-zA-Z0-9_]*$").unwrap();
        }

        if RE.is_match(name) {
            Ok(Self(name.to_string()))
        } else {
            Err(LigatureError(format!("Invalid Attribute name {}", name)))
        }
    }

    /// Returns the name of the given Arrow.
    pub fn name(&self) -> &str {
        &self.0
    }
}

/// An enum that represents all the currently supported Value types.
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub enum Value {
    /// An Entity.
    Entity(Entity),
    /// A String used for a Ligature literal
    StringLiteral(String),
    /// An i64 used for a Ligature literal
    IntegerLiteral(i64),
    /// An f64 used for a Ligature literal
    FloatLiteral(f64),
}

/// A set of enums used to express range queries when it makes sense for that type (ie no support for BooleanLiteralRange or UnknownLiteralRange since they don't make sense).
#[derive(Debug)]
pub enum Range {
    /// Represents a String range using basic String comparisons.
    StringLiteralRange {
        /// The starting String (inclusive)
        start: String,
        /// The end String (exclusive)
        end: String,
    },
    /// Represents a String range using basic i64 comparisons.
    IntegerLiteralRange {
        /// The starting i64 (inclusive)
        start: i64,
        /// The end i64 (exclusive)
        end: i64,
    },
    /// Represents a String range using basic f64 comparisons.
    FloatLiteralRange {
        /// The starting f64 (inclusive)
        start: f64,
        /// The end f64 (exclusive)
        end: f64,
    },
}

/// A Statement is a grouping of an Entity, an Attribute, and a Value.
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct Statement {
    /// The Entity of a Statement
    pub entity: Entity,
    /// The Attribute of a Statement
    pub attribute: Attribute,
    /// The Value of a Statement
    pub value: Value,
    /// The Context of this Statement
    pub context: Entity,
}

/// A general struct for representing errors involving Ligature.
/// TODO should probably be an enum with a bunch of specific cases
#[derive(Debug, PartialEq, Eq)]
pub struct LigatureError(pub String);

/// A trait that all Ligature implementations implement.
pub trait Ligature {
    /// Returns all Datasets in a Ligature instance.
    fn all_datasets(&self) -> Box<dyn Iterator<Item = Result<Dataset, LigatureError>>>;

    /// Check if a given Dataset exists.
    fn dataset_exists(&self, dataset: &Dataset) -> Result<bool, LigatureError>;

    /// Returns all Datasets in a Ligature instance that start with the given prefix.
    fn match_datasets_prefix(
        &self,
        prefix: &str,
    ) -> Box<dyn Iterator<Item = Result<Dataset, LigatureError>>>;

    /// Returns all Datasets in a Ligature instance that are in a given range (inclusive, exclusive].
    fn match_datasets_range(
        &self,
        start: &str,
        end: &str,
    ) -> Box<dyn Iterator<Item = Result<Dataset, LigatureError>>>;

    /// Creates a dataset with the given name.
    /// TODO should probably return its own error type { InvalidDataset, DatasetExists, CouldNotCreateDataset }
    fn create_dataset(&self, dataset: &Dataset) -> Result<(), LigatureError>;

    /// Deletes a dataset with the given name.
    /// TODO should probably return its own error type { InvalidDataset, CouldNotDeleteDataset }
    fn delete_dataset(&self, dataset: &Dataset) -> Result<(), LigatureError>;

    /// Initiazes a QueryTx
    /// TODO should probably return its own error type CouldNotInitializeQueryTx
    fn query<T>(&self, dataset: &Dataset, f: QueryFn<T>) -> Result<T, LigatureError>;

    /// Initiazes a WriteTx
    /// TODO should probably return its own error type CouldNotInitializeWriteTx
    fn write<T>(&self, dataset: &Dataset, f: WriteFn<T>) -> Result<T, LigatureError>;
}

/// An Fn that is used when making a Query tranaction.
pub type QueryFn<T> = Box<dyn Fn(Box<&dyn QueryTx>) -> Result<T, LigatureError>>;

/// An Fn that is used when making a Write transaction.
pub type WriteFn<T> = Box<dyn Fn(Box<&dyn WriteTx>) -> Result<T, LigatureError>>;

/// Represents a QueryTx within the context of a Ligature instance and a single Dataset
pub trait QueryTx {
    /// Returns all Statements in this Dataset.
    fn all_statements(
        &self,
    ) -> Box<dyn Iterator<Item = Result<Statement, LigatureError>> + '_>;

    /// Returns all Statements that match the given criteria.
    /// If a parameter is None then it matches all, so passing all Nones is the same as calling all_statements.
    fn match_statements(
        &self,
        source: Option<Entity>,
        arrow: Option<Attribute>,
        target: Option<Value>,
    ) -> Box<dyn Iterator<Item = Result<Statement, LigatureError>> + '_>;

    /// Returns all Statements that match the given criteria.
    /// If a parameter is None then it matches all.
    fn match_statements_range(
        &self,
        source: Option<Entity>,
        arrow: Option<Attribute>,
        target: Range,
    ) -> Box<dyn Iterator<Item = Result<Statement, LigatureError>> + '_>;

    /// Returns the Statement for the given context.
    fn statement_for_context(
        &self,
        context: &Entity,
    ) -> Result<Option<Statement>, LigatureError>;
}

/// Represents a WriteTx within the context of a Ligature instance and a single Dataset
pub trait WriteTx {
    /// Creates a new, unique Entity within this Dataset.
    /// Note: Entitys are shared across named graphs in a given Dataset.
    fn new_entity(&self) -> Result<Entity, LigatureError>;

    /// Adds a given Statement to this Dataset.
    /// If the Statement already exists nothing happens (TODO maybe add it with a new context?).
    /// Note: Potentally could trigger a ValidationError
    fn add_statement(&self, statement: &Statement) -> Result<Statement, LigatureError>;

    /// Removes a given Statement from this Dataset.
    /// If the Statement doesn't exist nothing happens and returns Ok(false).
    /// This function returns Ok(true) only if the given Statement was found and removed.
    /// Note: Potentally could trigger a ValidationError.
    fn remove_statement(
        &self,
        persisted_statement: &Statement,
    ) -> Result<bool, LigatureError>;

    /// Cancels this transaction so that none of the changes made so far will be stored.
    /// This also closes this transaction so no other methods can be called without returning a LigatureError.
    fn cancel(&self) -> Result<(), LigatureError>;
}
<|endoftext|>