<commit_before>extern crate cookie as _cookie;
#[macro_use] extern crate error_chain;
#[macro_use] extern crate iron;
extern crate rand;
#[cfg(feature = "redis-backend")] extern crate redis;
#[cfg(feature = "redis-backend")] extern crate r2d2;
#[cfg(feature = "redis-backend")] extern crate r2d2_redis;

use iron::prelude::*;
use iron::middleware::{AroundMiddleware,Handler};
use iron::typemap;

pub mod backends;
pub mod errors;

/// Re-export of the cookie crate
pub mod cookie {
    pub use _cookie::*;
}

/// A simple key-value storage interface that is internally used by `Session`. After request
/// handling the `write` method is called where the session backend has the chance to e.g. set
/// cookies or otherwise modify the response.
pub trait RawSession {
    fn get_raw(&self, key: &str) -> IronResult<Option<String>>;
    fn set_raw(&mut self, key: &str, value: String) -> IronResult<()>;
    fn clear(&mut self) -> IronResult<()>;
    fn write(&self, response: &mut Response) -> IronResult<()>;
}

pub trait SessionBackend: Send + Sync + 'static {
    type S: RawSession;

    /// Parse the session before request handling and return the data in parsed form.
    fn from_request(&self, request: &mut Request) -> Self::S;
}

/// The most important type, the middleware you need to register.
///
/// First parameter is a session backend, which determines how your session data is actually
/// stored. Depending on whether you store your data clientside (signed cookies) or serverside
/// (e.g. Redis and a session key) you're going to have different security properties.
pub struct SessionStorage<B: SessionBackend> {
    backend: B
}

impl<B: SessionBackend> SessionStorage<B> {
    pub fn new(backend: B) -> Self {
        SessionStorage {
            backend: backend
        }
    }
}

/// The high-level interface you use to modify session data. You obtain this object with
/// `request.session()`.
pub struct Session {
    inner: Box<RawSession>,
    has_changed: bool,
}

impl Session {
    fn new(s: Box<RawSession>) -> Self {
        Session {
            inner: s,
            has_changed: false
        }
    }
}

/// A typed interface to the string-to-string mapping. Each type represents a key, each instance of
/// a type can be serialized into a value.
pub trait Value: Sized + 'static {
    fn get_key() -> &'static str;
    fn into_raw(self) -> String;
    fn from_raw(value: String) -> Option<Self>;
}

impl Session {
    /// Get a `Value` from the session.
    pub fn get<T: Value + Sized + 'static>(&self) -> IronResult<Option<T>> {
        Ok(try!(self.inner.get_raw(T::get_key())).and_then(T::from_raw))
    }

    /// Set a `Value` in the session.
    pub fn set<T: Value>(&mut self, t: T) -> IronResult<()> {
        // FIXME: Equality check for less unnecessary writes
        self.has_changed = true;
        self.inner.set_raw(T::get_key(), t.into_raw())
    }

    /// Clear/delete the session
    pub fn clear(&mut self) -> IronResult<()> {
        // FIXME: Equality check for less unnecessary writes
        self.has_changed = true;
        self.inner.clear()
    }
}

struct SessionKey;
impl typemap::Key for SessionKey { type Value = Session; }

impl<B: SessionBackend> AroundMiddleware for SessionStorage<B> {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        Box::new(move |req: &mut Request| -> IronResult<Response> {
            let s = self.backend.from_request(req);
            req.extensions.insert::<SessionKey>(Session::new(Box::new(s)));
            let mut res = handler.handle(req);
            let s = req.extensions.remove::<SessionKey>().unwrap();
            if s.has_changed {
                match res {
                    Ok(ref mut r) => try!(s.inner.write(r)),
                    Err(ref mut e) => try!(s.inner.write(&mut e.response))
                }
            };
            res
        })
    }
}

/// The helper trait to obtain your session data from a request.
pub trait SessionRequestExt {
    fn session(&mut self) -> &mut Session;
}

impl<'a, 'b> SessionRequestExt for Request<'a, 'b> {
    fn session(&mut self) -> &mut Session {
        self.extensions.get_mut::<SessionKey>().unwrap()
    }
}

fn get_default_cookie(key: String, value: String) -> cookie::Cookie {
    let mut rv = cookie::Cookie::new(key, value);
    rv.httponly = true;
    rv.path = Some("/".to_owned());
    rv
}

/// A module with some important traits to star-import.
pub mod traits {
    pub use super::{SessionRequestExt};
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Fix unused warning<commit_after>extern crate cookie as _cookie;
#[macro_use] extern crate error_chain;
extern crate iron;
extern crate rand;
#[cfg(feature = "redis-backend")] extern crate redis;
#[cfg(feature = "redis-backend")] extern crate r2d2;
#[cfg(feature = "redis-backend")] extern crate r2d2_redis;

use iron::prelude::*;
use iron::middleware::{AroundMiddleware,Handler};
use iron::typemap;

pub mod backends;
pub mod errors;

/// Re-export of the cookie crate
pub mod cookie {
    pub use _cookie::*;
}

/// A simple key-value storage interface that is internally used by `Session`. After request
/// handling the `write` method is called where the session backend has the chance to e.g. set
/// cookies or otherwise modify the response.
pub trait RawSession {
    fn get_raw(&self, key: &str) -> IronResult<Option<String>>;
    fn set_raw(&mut self, key: &str, value: String) -> IronResult<()>;
    fn clear(&mut self) -> IronResult<()>;
    fn write(&self, response: &mut Response) -> IronResult<()>;
}

pub trait SessionBackend: Send + Sync + 'static {
    type S: RawSession;

    /// Parse the session before request handling and return the data in parsed form.
    fn from_request(&self, request: &mut Request) -> Self::S;
}

/// The most important type, the middleware you need to register.
///
/// First parameter is a session backend, which determines how your session data is actually
/// stored. Depending on whether you store your data clientside (signed cookies) or serverside
/// (e.g. Redis and a session key) you're going to have different security properties.
pub struct SessionStorage<B: SessionBackend> {
    backend: B
}

impl<B: SessionBackend> SessionStorage<B> {
    pub fn new(backend: B) -> Self {
        SessionStorage {
            backend: backend
        }
    }
}

/// The high-level interface you use to modify session data. You obtain this object with
/// `request.session()`.
pub struct Session {
    inner: Box<RawSession>,
    has_changed: bool,
}

impl Session {
    fn new(s: Box<RawSession>) -> Self {
        Session {
            inner: s,
            has_changed: false
        }
    }
}

/// A typed interface to the string-to-string mapping. Each type represents a key, each instance of
/// a type can be serialized into a value.
pub trait Value: Sized + 'static {
    fn get_key() -> &'static str;
    fn into_raw(self) -> String;
    fn from_raw(value: String) -> Option<Self>;
}

impl Session {
    /// Get a `Value` from the session.
    pub fn get<T: Value + Sized + 'static>(&self) -> IronResult<Option<T>> {
        Ok(try!(self.inner.get_raw(T::get_key())).and_then(T::from_raw))
    }

    /// Set a `Value` in the session.
    pub fn set<T: Value>(&mut self, t: T) -> IronResult<()> {
        // FIXME: Equality check for less unnecessary writes
        self.has_changed = true;
        self.inner.set_raw(T::get_key(), t.into_raw())
    }

    /// Clear/delete the session
    pub fn clear(&mut self) -> IronResult<()> {
        // FIXME: Equality check for less unnecessary writes
        self.has_changed = true;
        self.inner.clear()
    }
}

struct SessionKey;
impl typemap::Key for SessionKey { type Value = Session; }

impl<B: SessionBackend> AroundMiddleware for SessionStorage<B> {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        Box::new(move |req: &mut Request| -> IronResult<Response> {
            let s = self.backend.from_request(req);
            req.extensions.insert::<SessionKey>(Session::new(Box::new(s)));
            let mut res = handler.handle(req);
            let s = req.extensions.remove::<SessionKey>().unwrap();
            if s.has_changed {
                match res {
                    Ok(ref mut r) => try!(s.inner.write(r)),
                    Err(ref mut e) => try!(s.inner.write(&mut e.response))
                }
            };
            res
        })
    }
}

/// The helper trait to obtain your session data from a request.
pub trait SessionRequestExt {
    fn session(&mut self) -> &mut Session;
}

impl<'a, 'b> SessionRequestExt for Request<'a, 'b> {
    fn session(&mut self) -> &mut Session {
        self.extensions.get_mut::<SessionKey>().unwrap()
    }
}

fn get_default_cookie(key: String, value: String) -> cookie::Cookie {
    let mut rv = cookie::Cookie::new(key, value);
    rv.httponly = true;
    rv.path = Some("/".to_owned());
    rv
}

/// A module with some important traits to star-import.
pub mod traits {
    pub use super::{SessionRequestExt};
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>use api_client::{ApiClient, Error};
use serde_json;
use serde_json::Value;
use std::collections::HashMap;
use std::io;
use std::io::{Cursor, Read, ErrorKind};
use utils::decode_list;

chef_json_type!(NodeJsonClass, "Chef::Node");
chef_json_type!(NodeChefType, "node");

#[derive(Debug,Clone,Serialize,Deserialize,Default)]
pub struct Node {
    #[serde(default)]
    pub name: Option<String>,
    #[serde(default)]
    chef_type: NodeChefType,
    #[serde(default)]
    json_class: NodeJsonClass,
    #[serde(default)]
    pub chef_environment: String,
    #[serde(default)]
    pub run_list: Vec<String>,
    #[serde(default)]
    pub normal: HashMap<String, Value>,
    #[serde(default)]
    pub automatic: HashMap<String, Value>,
    #[serde(default)]
    pub default: HashMap<String, Value>,
    #[serde(default,rename(json="override"))]
    pub overrides: HashMap<String, Value>,
}

impl Read for Node {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if let Ok(node) = serde_json::to_vec(self) {
            let mut node = Cursor::new(node.as_ref() as &[u8]);
            Read::read(&mut node, buf)
        } else {
            Err(io::Error::new(ErrorKind::InvalidData, "Failed to convert node to JSON"))
        }
    }
}

impl Node {
    pub fn new<S>(name: S) -> Node
        where S: Into<String>
    {
        Node { name: Some(name.into()), ..Default::default() }
    }

    pub fn fetch(client: &ApiClient, name: &str) -> Result<Node, Error> {
        let org = &client.config.organization_path();
        let path = format!("{}/nodes/{}", org, name);
        client.get(path.as_ref()).and_then(|r| r.from_json::<Node>())
    }

    pub fn save(&self, client: &ApiClient) -> Result<Node, Error> {
        let name = &self.name.clone().unwrap();
        let org = &client.config.organization_path();
        let path = format!("{}/nodes/{}", org, name);
        client.put(path.as_ref(), self).and_then(|r| r.from_json::<Node>())
    }

    pub fn delete(&self, client: &ApiClient) -> Result<Node, Error> {
        let name = &self.name.clone().unwrap();
        let org = &client.config.organization_path();
        let path = format!("{}/nodes/{}", org, name);
        client.delete(path.as_ref()).and_then(|r| r.from_json::<Node>())
    }

    pub fn from_json<R>(r: R) -> Result<Node, Error>
        where R: Read
    {
        serde_json::from_reader::<R, Node>(r).map_err(|e| Error::Json(e))
    }
}

pub fn delete_node(client: &ApiClient, name: &str) -> Result<Node, Error> {
    let org = &client.config.organization_path();
    let path = format!("{}/nodes/{}", org, name);
    client.delete(path.as_ref()).and_then(|r| r.from_json::<Node>())
}

#[derive(Debug)]
pub struct NodeList {
    count: usize,
    nodes: Vec<String>,
    client: ApiClient,
}

impl NodeList {
    pub fn new(client: &ApiClient) -> NodeList {
        let org = &client.config.organization_path();
        let path = format!("{}/nodes", org);
        client.get(path.as_ref())
              .and_then(|r| decode_list(r))
              .and_then(|list| {
                  Ok(NodeList {
                      nodes: list,
                      count: 0,
                      client: client.clone(),
                  })
              })
              .unwrap()
    }
}

impl Iterator for NodeList {
    type Item = Result<Node, Error>;

    fn count(self) -> usize {
        self.nodes.len()
    }

    fn next(&mut self) -> Option<Result<Node, Error>> {
        if self.count < self.nodes.len() {
            let ref name = self.nodes[self.count];
            self.count += 1;
            Some(Node::fetch(&self.client, name.as_ref()))
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Node;
    use std::fs::File;

    #[test]
    fn test_node_from_file() {
        let fh = File::open("fixtures/node.json").unwrap();
        let node = Node::from_json(fh).unwrap();
        assert_eq!(node.name.unwrap(), "test")
    }
}
<commit_msg>tidy up node a smidgeon<commit_after>use api_client::{ApiClient, Error};
use serde_json;
use serde_json::Value;
use std::collections::HashMap;
use std::io;
use std::io::{Cursor, Read, ErrorKind};
use utils::decode_list;

chef_json_type!(NodeJsonClass, "Chef::Node");
chef_json_type!(NodeChefType, "node");

#[derive(Debug,Clone,Serialize,Deserialize,Default)]
pub struct Node {
    #[serde(default)]
    pub name: Option<String>,
    #[serde(default)]
    chef_type: NodeChefType,
    #[serde(default)]
    json_class: NodeJsonClass,
    #[serde(default)]
    pub chef_environment: String,
    #[serde(default)]
    pub run_list: Vec<String>,
    #[serde(default)]
    pub normal: HashMap<String, Value>,
    #[serde(default)]
    pub automatic: HashMap<String, Value>,
    #[serde(default)]
    pub default: HashMap<String, Value>,
    #[serde(default,rename(json="override"))]
    pub overrides: HashMap<String, Value>,
}

impl Read for Node {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if let Ok(node) = serde_json::to_vec(self) {
            let mut node = Cursor::new(node.as_ref() as &[u8]);
            Read::read(&mut node, buf)
        } else {
            Err(io::Error::new(ErrorKind::InvalidData, "Failed to convert node to JSON"))
        }
    }
}

impl Node {
    pub fn new<S>(name: S) -> Node
        where S: Into<String>
    {
        Node { name: Some(name.into()), ..Default::default() }
    }

    pub fn fetch<S: Into<String>>(client: &ApiClient, name: S) -> Result<Node, Error> {
        let org = &client.config.organization_path();
        let path = format!("{}/nodes/{}", org, name.into());
        client.get(path.as_ref()).and_then(|r| r.from_json::<Node>())
    }

    pub fn save(&self, client: &ApiClient) -> Result<Node, Error> {
        let name = &self.name.clone().unwrap();
        let org = &client.config.organization_path();
        let path = format!("{}/nodes/{}", org, name);
        client.put(path.as_ref(), self).and_then(|r| r.from_json::<Node>())
    }

    pub fn delete(&self, client: &ApiClient) -> Result<Node, Error> {
        let name = &self.name.clone().unwrap();
        let org = &client.config.organization_path();
        let path = format!("{}/nodes/{}", org, name);
        client.delete(path.as_ref()).and_then(|r| r.from_json::<Node>())
    }

    pub fn from_json<R>(r: R) -> Result<Node, Error>
        where R: Read
    {
        serde_json::from_reader::<R, Node>(r).map_err(|e| Error::Json(e))
    }
}

pub fn delete_node(client: &ApiClient, name: &str) -> Result<Node, Error> {
    let org = &client.config.organization_path();
    let path = format!("{}/nodes/{}", org, name);
    client.delete(path.as_ref()).and_then(|r| r.from_json::<Node>())
}

#[derive(Debug)]
pub struct NodeList {
    count: usize,
    nodes: Vec<String>,
    client: ApiClient,
}

impl NodeList {
    pub fn new(client: &ApiClient) -> NodeList {
        let org = &client.config.organization_path();
        let path = format!("{}/nodes", org);
        client.get(path.as_ref())
              .and_then(|r| decode_list(r))
              .and_then(|list| {
                  Ok(NodeList {
                      nodes: list,
                      count: 0,
                      client: client.clone(),
                  })
              })
              .unwrap()
    }
}

impl Iterator for NodeList {
    type Item = Result<Node, Error>;

    fn count(self) -> usize {
        self.nodes.len()
    }

    fn next(&mut self) -> Option<Result<Node, Error>> {
        if self.count < self.nodes.len() {
            let ref name = self.nodes[self.count];
            self.count += 1;
            Some(Node::fetch(&self.client, name.as_ref()))
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Node;
    use std::fs::File;

    #[test]
    fn test_node_from_file() {
        let fh = File::open("fixtures/node.json").unwrap();
        let node = Node::from_json(fh).unwrap();
        assert_eq!(node.name.unwrap(), "test")
    }
}
<|endoftext|>


<commit_before>#![crate_id = "fragments#0.1-pre"]

#![comment = "A simple template library for Rust"]
#![license = "MIT"]
#![crate_type = "lib"]
#![crate_type = "rlib"]

#![doc(html_root_url = "http://www.rust-ci.org/Ogeon/fragments/doc/")]

extern crate collections;

use std::fmt;
use std::from_str::FromStr;
use std::io::{BufReader, IoError, EndOfFile};
use std::vec::Vec;
use collections::hashmap::{HashMap, HashSet};

type ParserState = Option<fn(&mut Buffer) -> ParserResult>;

struct ParserResult {
	token: Token,
	next_parser: ParserState
}

#[deriving(Eq, TotalEq, Show)]
enum Token {
	String(~str),
	Placeholder(~str),
	Conditional(~str, bool, Vec<Token>)
}

///A string template with placeholders and conditional content.
///
///Placeholders are written as `[[:label]]`, where `label` becomes the name of the placeholder.
///The label is then used to insert content: `my_template.insert(~"label", my_content);`.
///The assigned content for a placeholder can be anything that implements `Show`.
///Even other templates may be inserted, which allows a more atomic structure.
///
///Conditional segments are surrounded by `[[?label]]...[[/]]`, where `label` becomes the name of the condition,
///and they are used to display content depending on whether its label exists in the `conditions` set.
///`[[/]]` marks the end of a block and may contain other characters after the `/`, which may be useful for labeling the end mark.
///Conditions can be made negative by writing `[[?!label]]...[[/]]`, which makes the content visible if the label
///is missing from the `conditions` set.
///
///Any character can be escaped by writing `\` before it. It can be used like this: `\[[[:label1]], [[:label2]]]`
///which will result in `[content1, content2]`, since the first `[` will be ignored by the parser and just added to the
///rest of the content.
pub struct Template {
	///Content for the placeholders
	content: HashMap<~str, ~fmt::Show: Send>,
	///Conditional switches
	conditions: HashSet<~str>,
	priv tokens: Vec<Token>
}

impl Template {
	#[inline]
	pub fn from_buffer(b: &mut Buffer) -> Template {
		Template {
			content: HashMap::new(),
			conditions: HashSet::new(),
			tokens: parse_block(b)
		}
	}

	///Convenience method for inserting content.
	#[inline]
	pub fn insert<T: fmt::Show + Send>(&mut self, placeholder: ~str, item: ~T) {
		self.content.insert(placeholder, item as ~fmt::Show: Send);
	}

	///Convenience method for setting a condition.
	#[inline]
	pub fn set(&mut self, condition: ~str, value: bool) {
		if value {
			self.conditions.insert(condition);
		} else {
			self.conditions.remove(&condition);
		}
	}

	fn format_tokens(&self, tokens: &Vec<Token>, f: &mut fmt::Formatter) -> fmt::Result {
		for token in tokens.iter() {
			let res = match token {
				&String(ref s) => f.buf.write_str(*s),

				&Placeholder(ref k) => {
					match self.content.find(k) {
						Some(value) => value.fmt(f),
						None => Ok(())
					}
				},

				&Conditional(ref k, expected, ref tokens) => {
					if self.conditions.contains(k) == expected {
						self.format_tokens(tokens, f)
					} else {
						Ok(())
					}
				}
			};

			match res {
				Err(e) => return Err(e),
				_ => {}
			}
		}

		Ok(())
	}
}

impl FromStr for Template {
	///Creates a new `Template` from a string.
	fn from_str(s: &str) -> Option<Template> {
		Some(Template::from_buffer(&mut BufReader::new(s.as_bytes())))
	}
}

impl fmt::Show for Template {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.format_tokens(&self.tokens, f)
	}
}

fn parse_block(b: &mut Buffer) -> Vec<Token> {
	let mut tokens = vec!();
	let mut parser = parse_string;

	loop {
		let ParserResult{token: token, next_parser: next} = parser(b);

		tokens.push(token);

		match next {
			Some(p) => parser = p,
			None => break
		}
	}

	tokens
}

fn parse_string(b: &mut Buffer) -> ParserResult {
	let mut content = ~"";

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						content.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok('[') => {
				match b.read_char() {
					Ok('[') => {
						match b.read_char() {
							Ok(':') => return ParserResult{
								token: String(content),
								next_parser: Some(parse_placeholder)
							},
							Ok('?') => return ParserResult{
								token: String(content),
								next_parser: Some(parse_conditional)
							},
							Ok('/') => {
								skip_to_token_end(b);

								return ParserResult{
									token: String(content),
									next_parser: None
								}
							},
							Ok(c) => fail!("Unknown token type: '{}'", c),
							Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
							Err(e) => fail!("{}", e)
						}
					},
					Ok(c) => {
						content.push_char('[');
						content.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => content.push_char('['),
					Err(e) => fail!("{}", e)
				}
			},
			Ok(c) => content.push_char(c),
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e)
		}
	}

	ParserResult{
		token: String(content),
		next_parser: None
	}
}

fn skip_to_token_end(b: &mut Buffer) {
	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(_) => {},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => break,
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e),
					_ => {}
				}
			},
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e),
			_ => {}
		}
	}
}

fn parse_placeholder(b: &mut Buffer) -> ParserResult {
	let mut label = ~"";

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => {
						return ParserResult{
							token: Placeholder(label),
							next_parser: Some(parse_string)
						}
					},
					Ok(c) => {
						label.push_char(']');
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => label.push_char(']'),
					Err(e) => fail!("{}", e)
				}
			},
			Ok(c) => label.push_char(c),
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e)
		}
	}

	ParserResult{
		token: Placeholder(label),
		next_parser: None
	}
}

fn parse_conditional(b: &mut Buffer) -> ParserResult {
	let mut label = ~"";
	let mut expected = true;
	let mut expected_set = false;

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => {
						return ParserResult{
							token: Conditional(label, expected, parse_block(b)),
							next_parser: Some(parse_string)
						}
					},
					Ok(c) => {
						label.push_char(']');
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => label.push_char(']'),
					Err(e) => fail!("{}", e)
				}
			},
			Ok('!') => {
				if label.len() == 0 && !expected_set {
					expected = false;
					expected_set = true;
				} else {
					label.push_char('!');
				}
			},
			Ok(c) => {
				label.push_char(c)
			},
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e)
		}
	}

	ParserResult{
		token: Conditional(label, expected, vec!()),
		next_parser: None
	}
}

#[cfg(test)]
mod test {
	use super::{Template, Placeholder, String};

	#[test]
	fn basic_tokens() {
		let template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
		assert_eq!(template.tokens.get(1), &Placeholder(~"name"));
		assert_eq!(template.tokens.get(2), &String(~"! This is a "));
		assert_eq!(template.tokens.get(3), &Placeholder(~"something"));
		assert_eq!(template.tokens.get(4), &String(~" template."));
	}

	#[test]
	#[should_fail]
	fn strange_tokens() {
		let _: Template = from_str("Hello, [[[:name]]]! This is a [[[[:something]] template.").unwrap();
	}

	#[test]
	fn escaped_tokens() {
		let template: Template = from_str("Hello, [[:name]]! Write placeholders like \\[[:this]] and escape them like \\\\\\[[:this]]").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
		assert_eq!(template.tokens.get(1), &Placeholder(~"name"));
		assert_eq!(template.tokens.get(2), &String(~"! Write placeholders like [[:this]] and escape them like \\[[:this]]"));
	}

	#[test]
	fn replacement() {
		let mut template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		template.insert(~"name", ~("Peter"));
		template.insert(~"something", ~("nice"));
		assert_eq!(template.to_str(), ~"Hello, Peter! This is a nice template.");
	}

	#[test]
	fn templates_in_templates() {
		let mut template1: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		let mut template2: ~Template = ~from_str("really [[:something]]").unwrap();
		template1.insert(~"name", ~("Peter"));
		template2.insert(~"something", ~("nice"));

		template1.insert(~"something", template2);

		assert_eq!(template1.to_str(), ~"Hello, Peter! This is a really nice template.");
	}

	#[test]
	fn conditional() {
		let mut template: Template = from_str("Hello, [[:name]]![[?condition]] The condition is true.[[/condition]]").unwrap();
		template.insert(~"name", ~("Peter"));
		assert_eq!(template.to_str(), ~"Hello, Peter!");
		template.set(~"condition", true);
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is true.");
	}

	#[test]
	fn conditional_switch() {
		let mut template: Template = from_str("Hello, [[:name]]! The condition is [[?condition]]true[[/condition]][[?!condition]]false[[/condition]].").unwrap();
		template.insert(~"name", ~("Peter"));
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is false.");
		template.set(~"condition", true);
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is true.");
	}
}<commit_msg>Fixed priv/pub<commit_after>#![crate_id = "fragments#0.1-pre"]

#![comment = "A simple template library for Rust"]
#![license = "MIT"]
#![crate_type = "lib"]
#![crate_type = "rlib"]

#![doc(html_root_url = "http://www.rust-ci.org/Ogeon/fragments/doc/")]

extern crate collections;

use std::fmt;
use std::from_str::FromStr;
use std::io::{BufReader, IoError, EndOfFile};
use std::vec::Vec;
use collections::hashmap::{HashMap, HashSet};

type ParserState = Option<fn(&mut Buffer) -> ParserResult>;

struct ParserResult {
	token: Token,
	next_parser: ParserState
}

#[deriving(Eq, TotalEq, Show)]
enum Token {
	String(~str),
	Placeholder(~str),
	Conditional(~str, bool, Vec<Token>)
}

///A string template with placeholders and conditional content.
///
///Placeholders are written as `[[:label]]`, where `label` becomes the name of the placeholder.
///The label is then used to insert content: `my_template.insert(~"label", my_content);`.
///The assigned content for a placeholder can be anything that implements `Show`.
///Even other templates may be inserted, which allows a more atomic structure.
///
///Conditional segments are surrounded by `[[?label]]...[[/]]`, where `label` becomes the name of the condition,
///and they are used to display content depending on whether its label exists in the `conditions` set.
///`[[/]]` marks the end of a block and may contain other characters after the `/`, which may be useful for labeling the end mark.
///Conditions can be made negative by writing `[[?!label]]...[[/]]`, which makes the content visible if the label
///is missing from the `conditions` set.
///
///Any character can be escaped by writing `\` before it. It can be used like this: `\[[[:label1]], [[:label2]]]`
///which will result in `[content1, content2]`, since the first `[` will be ignored by the parser and just added to the
///rest of the content.
pub struct Template {
	///Content for the placeholders
	pub content: HashMap<~str, ~fmt::Show: Send>,
	///Conditional switches
	pub conditions: HashSet<~str>,
	tokens: Vec<Token>
}

impl Template {
	#[inline]
	pub fn from_buffer(b: &mut Buffer) -> Template {
		Template {
			content: HashMap::new(),
			conditions: HashSet::new(),
			tokens: parse_block(b)
		}
	}

	///Convenience method for inserting content.
	#[inline]
	pub fn insert<T: fmt::Show + Send>(&mut self, placeholder: ~str, item: ~T) {
		self.content.insert(placeholder, item as ~fmt::Show: Send);
	}

	///Convenience method for setting a condition.
	#[inline]
	pub fn set(&mut self, condition: ~str, value: bool) {
		if value {
			self.conditions.insert(condition);
		} else {
			self.conditions.remove(&condition);
		}
	}

	fn format_tokens(&self, tokens: &Vec<Token>, f: &mut fmt::Formatter) -> fmt::Result {
		for token in tokens.iter() {
			let res = match token {
				&String(ref s) => f.buf.write_str(*s),

				&Placeholder(ref k) => {
					match self.content.find(k) {
						Some(value) => value.fmt(f),
						None => Ok(())
					}
				},

				&Conditional(ref k, expected, ref tokens) => {
					if self.conditions.contains(k) == expected {
						self.format_tokens(tokens, f)
					} else {
						Ok(())
					}
				}
			};

			match res {
				Err(e) => return Err(e),
				_ => {}
			}
		}

		Ok(())
	}
}

impl FromStr for Template {
	///Creates a new `Template` from a string.
	fn from_str(s: &str) -> Option<Template> {
		Some(Template::from_buffer(&mut BufReader::new(s.as_bytes())))
	}
}

impl fmt::Show for Template {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.format_tokens(&self.tokens, f)
	}
}

fn parse_block(b: &mut Buffer) -> Vec<Token> {
	let mut tokens = vec!();
	let mut parser = parse_string;

	loop {
		let ParserResult{token: token, next_parser: next} = parser(b);

		tokens.push(token);

		match next {
			Some(p) => parser = p,
			None => break
		}
	}

	tokens
}

fn parse_string(b: &mut Buffer) -> ParserResult {
	let mut content = ~"";

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						content.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok('[') => {
				match b.read_char() {
					Ok('[') => {
						match b.read_char() {
							Ok(':') => return ParserResult{
								token: String(content),
								next_parser: Some(parse_placeholder)
							},
							Ok('?') => return ParserResult{
								token: String(content),
								next_parser: Some(parse_conditional)
							},
							Ok('/') => {
								skip_to_token_end(b);

								return ParserResult{
									token: String(content),
									next_parser: None
								}
							},
							Ok(c) => fail!("Unknown token type: '{}'", c),
							Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
							Err(e) => fail!("{}", e)
						}
					},
					Ok(c) => {
						content.push_char('[');
						content.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => content.push_char('['),
					Err(e) => fail!("{}", e)
				}
			},
			Ok(c) => content.push_char(c),
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e)
		}
	}

	ParserResult{
		token: String(content),
		next_parser: None
	}
}

fn skip_to_token_end(b: &mut Buffer) {
	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(_) => {},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => break,
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e),
					_ => {}
				}
			},
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e),
			_ => {}
		}
	}
}

fn parse_placeholder(b: &mut Buffer) -> ParserResult {
	let mut label = ~"";

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => {
						return ParserResult{
							token: Placeholder(label),
							next_parser: Some(parse_string)
						}
					},
					Ok(c) => {
						label.push_char(']');
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => label.push_char(']'),
					Err(e) => fail!("{}", e)
				}
			},
			Ok(c) => label.push_char(c),
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e)
		}
	}

	ParserResult{
		token: Placeholder(label),
		next_parser: None
	}
}

fn parse_conditional(b: &mut Buffer) -> ParserResult {
	let mut label = ~"";
	let mut expected = true;
	let mut expected_set = false;

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
					Err(e) => fail!("{}", e)
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => {
						return ParserResult{
							token: Conditional(label, expected, parse_block(b)),
							next_parser: Some(parse_string)
						}
					},
					Ok(c) => {
						label.push_char(']');
						label.push_char(c);
					},
					Err(IoError{kind: EndOfFile, desc: _, detail: _}) => label.push_char(']'),
					Err(e) => fail!("{}", e)
				}
			},
			Ok('!') => {
				if label.len() == 0 && !expected_set {
					expected = false;
					expected_set = true;
				} else {
					label.push_char('!');
				}
			},
			Ok(c) => {
				label.push_char(c)
			},
			Err(IoError{kind: EndOfFile, desc: _, detail: _}) => break,
			Err(e) => fail!("{}", e)
		}
	}

	ParserResult{
		token: Conditional(label, expected, vec!()),
		next_parser: None
	}
}

#[cfg(test)]
mod test {
	use super::{Template, Placeholder, String};

	#[test]
	fn basic_tokens() {
		let template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
		assert_eq!(template.tokens.get(1), &Placeholder(~"name"));
		assert_eq!(template.tokens.get(2), &String(~"! This is a "));
		assert_eq!(template.tokens.get(3), &Placeholder(~"something"));
		assert_eq!(template.tokens.get(4), &String(~" template."));
	}

	#[test]
	#[should_fail]
	fn strange_tokens() {
		let _: Template = from_str("Hello, [[[:name]]]! This is a [[[[:something]] template.").unwrap();
	}

	#[test]
	fn escaped_tokens() {
		let template: Template = from_str("Hello, [[:name]]! Write placeholders like \\[[:this]] and escape them like \\\\\\[[:this]]").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
		assert_eq!(template.tokens.get(1), &Placeholder(~"name"));
		assert_eq!(template.tokens.get(2), &String(~"! Write placeholders like [[:this]] and escape them like \\[[:this]]"));
	}

	#[test]
	fn replacement() {
		let mut template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		template.insert(~"name", ~("Peter"));
		template.insert(~"something", ~("nice"));
		assert_eq!(template.to_str(), ~"Hello, Peter! This is a nice template.");
	}

	#[test]
	fn templates_in_templates() {
		let mut template1: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		let mut template2: ~Template = ~from_str("really [[:something]]").unwrap();
		template1.insert(~"name", ~("Peter"));
		template2.insert(~"something", ~("nice"));

		template1.insert(~"something", template2);

		assert_eq!(template1.to_str(), ~"Hello, Peter! This is a really nice template.");
	}

	#[test]
	fn conditional() {
		let mut template: Template = from_str("Hello, [[:name]]![[?condition]] The condition is true.[[/condition]]").unwrap();
		template.insert(~"name", ~("Peter"));
		assert_eq!(template.to_str(), ~"Hello, Peter!");
		template.set(~"condition", true);
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is true.");
	}

	#[test]
	fn conditional_switch() {
		let mut template: Template = from_str("Hello, [[:name]]! The condition is [[?condition]]true[[/condition]][[?!condition]]false[[/condition]].").unwrap();
		template.insert(~"name", ~("Peter"));
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is false.");
		template.set(~"condition", true);
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is true.");
	}
}<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![feature(unsafe_destructor)]
#![feature(associated_types)]
#![unstable]

//! A library for setting current values for stack scope,
//! such as application structure.

use std::cell::RefCell;
use std::intrinsics::TypeId;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{ Occupied, Vacant };
use std::ops::{ Deref, DerefMut };

// Stores the current pointers for concrete types.
thread_local!(static KEY_CURRENT: RefCell<HashMap<TypeId, uint>>
    = RefCell::new(HashMap::new()));

/// Puts back the previous current pointer.
#[unstable]
pub struct CurrentGuard<'a, T: 'a> {
    _val: &'a mut T,
    old_ptr: Option<uint>
}

#[unstable]
impl<'a, T: 'static> CurrentGuard<'a, T> {
    /// Creates a new current guard.
    #[unstable]
    pub fn new(val: &mut T) -> CurrentGuard<T> {
        let id = TypeId::of::<T>();
        let ptr = val as *mut T as uint;
        let old_ptr = KEY_CURRENT.with(|current| {
            match current.borrow_mut().entry(id) {
                Occupied(mut entry) => Some(entry.set(ptr)),
                Vacant(entry) => {
                    entry.set(ptr);
                    None
                }
            }
        });
        CurrentGuard { old_ptr: old_ptr, _val: val }
    }
}

#[unsafe_destructor]
impl<'a, T: 'static> Drop for CurrentGuard<'a, T> {
    fn drop(&mut self) {
        let id = TypeId::of::<T>();
        match self.old_ptr {
            None => {
                KEY_CURRENT.with(|current| {
                    current.borrow_mut().remove(&id);
                });
                return;
            }
            Some(old_ptr) => {
                KEY_CURRENT.with(|current| {
                    match current.borrow_mut().entry(id) {
                        Occupied(mut entry) => { entry.set(old_ptr); }
                        Vacant(entry) => { entry.set(old_ptr); }
                    };
                });
            }
        };
    }
}

/// The current value of a type.
#[unstable]
pub struct Current<T>(());

#[unstable]
impl<T: 'static> Current<T> {
    /// Creates a new current object
    #[unstable]
    pub unsafe fn new() -> Current<T> { Current(()) }

    /// Gets mutable reference to current object.
    /// Requires mutable reference to prevent access to globals in safe code,
    /// and to prevent mutable borrows of same value in scope.
    /// Is unsafe because returned reference inherits lifetime from argument.
    #[unstable]
    pub unsafe fn current(&mut self) -> Option<&mut T> {
        use std::mem::transmute;
        let id = TypeId::of::<T>();
        let ptr: Option<uint> = KEY_CURRENT.with(|current| {
                current.borrow().get(&id).map(|id| *id)
            });
        let ptr = match ptr { None => { return None; } Some(x) => x };
        Some(transmute(ptr as *mut T))
    }

    /// Unwraps mutable reference to current object,
    /// but with nicer error message.
    #[unstable]
    pub unsafe fn current_unwrap(&mut self) -> &mut T {
        match self.current() {
            None => {
                use std::intrinsics::get_tydesc;
                let name = (*get_tydesc::<T>()).name;
                panic!("No current `{}` is set", name);
            }
            Some(x) => x
        }
    }
}

impl<T: 'static> Deref for Current<T> {
    type Target = T;

    #[inline(always)]
    fn deref<'a>(&'a self) -> &'a T {
        use std::mem::transmute;
        unsafe {
            // Current does not contain anything,
            // so it is safe to transmute to mutable.
            transmute::<_, &'a mut Current<T>>(self).current_unwrap()
        }
    }
}

impl<T: 'static> DerefMut for Current<T> {
    #[inline(always)]
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { self.current_unwrap() }
    }
}
<commit_msg>Upgrade to latest Rust<commit_after>#![deny(missing_docs)]
#![feature(unsafe_destructor)]
#![feature(associated_types)]
#![unstable]

//! A library for setting current values for stack scope,
//! such as application structure.

use std::cell::RefCell;
use std::intrinsics::TypeId;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{ Occupied, Vacant };
use std::ops::{ Deref, DerefMut };

// Stores the current pointers for concrete types.
thread_local!(static KEY_CURRENT: RefCell<HashMap<TypeId, uint>>
    = RefCell::new(HashMap::new()));

/// Puts back the previous current pointer.
#[unstable]
pub struct CurrentGuard<'a, T: 'a> {
    _val: &'a mut T,
    old_ptr: Option<uint>
}

#[unstable]
impl<'a, T: 'static> CurrentGuard<'a, T> {
    /// Creates a new current guard.
    #[unstable]
    pub fn new(val: &mut T) -> CurrentGuard<T> {
        let id = TypeId::of::<T>();
        let ptr = val as *mut T as uint;
        let old_ptr = KEY_CURRENT.with(|current| {
            match current.borrow_mut().entry(&id) {
                Occupied(mut entry) => Some(entry.insert(ptr)),
                Vacant(entry) => {
                    entry.insert(ptr);
                    None
                }
            }
        });
        CurrentGuard { old_ptr: old_ptr, _val: val }
    }
}

#[unsafe_destructor]
impl<'a, T: 'static> Drop for CurrentGuard<'a, T> {
    fn drop(&mut self) {
        let id = TypeId::of::<T>();
        match self.old_ptr {
            None => {
                KEY_CURRENT.with(|current| {
                    current.borrow_mut().remove(&id);
                });
                return;
            }
            Some(old_ptr) => {
                KEY_CURRENT.with(|current| {
                    match current.borrow_mut().entry(&id) {
                        Occupied(mut entry) => { entry.insert(old_ptr); }
                        Vacant(entry) => { entry.insert(old_ptr); }
                    };
                });
            }
        };
    }
}

/// The current value of a type.
#[unstable]
pub struct Current<T>(());

#[unstable]
impl<T: 'static> Current<T> {
    /// Creates a new current object
    #[unstable]
    pub unsafe fn new() -> Current<T> { Current(()) }

    /// Gets mutable reference to current object.
    /// Requires mutable reference to prevent access to globals in safe code,
    /// and to prevent mutable borrows of same value in scope.
    /// Is unsafe because returned reference inherits lifetime from argument.
    #[unstable]
    pub unsafe fn current(&mut self) -> Option<&mut T> {
        use std::mem::transmute;
        let id = TypeId::of::<T>();
        let ptr: Option<uint> = KEY_CURRENT.with(|current| {
                current.borrow().get(&id).map(|id| *id)
            });
        let ptr = match ptr { None => { return None; } Some(x) => x };
        Some(transmute(ptr as *mut T))
    }

    /// Unwraps mutable reference to current object,
    /// but with nicer error message.
    #[unstable]
    pub unsafe fn current_unwrap(&mut self) -> &mut T {
        match self.current() {
            None => {
                use std::intrinsics::get_tydesc;
                let name = (*get_tydesc::<T>()).name;
                panic!("No current `{}` is set", name);
            }
            Some(x) => x
        }
    }
}

impl<T: 'static> Deref for Current<T> {
    type Target = T;

    #[inline(always)]
    fn deref<'a>(&'a self) -> &'a T {
        use std::mem::transmute;
        unsafe {
            // Current does not contain anything,
            // so it is safe to transmute to mutable.
            transmute::<_, &'a mut Current<T>>(self).current_unwrap()
        }
    }
}

impl<T: 'static> DerefMut for Current<T> {
    #[inline(always)]
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { self.current_unwrap() }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name = "c_compat"]
#![crate_type = "lib"]

#![feature(default_type_params)]

extern crate libc;

#[cfg(test)]
extern crate test;

pub mod c_str;
<commit_msg>Added a crate-level doc comment<commit_after>// Copyright 2014 Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # C compatibility helpers
//!
//! This library provides utilities for working with foreign function
//! interfaces using data layout and allocation conventions of the
//! C language.

#![crate_name = "c_compat"]
#![crate_type = "lib"]

#![feature(default_type_params)]

extern crate libc;

#[cfg(test)]
extern crate test;

pub mod c_str;
<|endoftext|>


<commit_before>//! A dead-simple test helper for rust.
//!
//! Example
//! --------
//!
//! ```rust
//! use bear::fixture;
//!
//! // Get a content of 'tests/fixtures/hello.txt'
//! let content = fixture("hello.txt");
//!
//! /* Do whatever you want with it */
//! ```

#![unstable]
#![doc(html_logo_url    = "https://simnalamburt.github.io/bear/cute.png",
       html_favicon_url = "https://simnalamburt.github.io/bear/cute.png",
       html_root_url    = "https://simnalamburt.github.io/bear")]

#![feature(path, fs, io)]
#![deny(warnings, missing_docs)]

use std::path::Path;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;

/// Open a file from the 'tests/fixtures' directory, and return its content as a `String`
///
/// Example
/// --------
///
/// ```rust
/// use bear::fixture;
///
/// // Get a content of 'tests/fixtures/hello.txt'
/// let content = fixture("hello.txt");
///
/// /* Do whatever you want with it */
/// ```
pub fn fixture(filename: &str) -> String {
    let path = Path::new("tests").join("fixtures").join(filename);
    let file = File::open(&path).unwrap();
    let mut reader = BufReader::new(file);

    let mut ret = String::new();

    reader.read_to_string(&mut ret).unwrap();

    ret
}
<commit_msg>Use stable Rust<commit_after>//! A dead-simple test helper for rust.
//!
//! Example
//! --------
//!
//! ```rust
//! use bear::fixture;
//!
//! // Get a content of 'tests/fixtures/hello.txt'
//! let content = fixture("hello.txt");
//!
//! // Do whatever you want with it
//! ```

#![doc(html_logo_url    = "https://simnalamburt.github.io/bear/cute.png",
       html_favicon_url = "https://simnalamburt.github.io/bear/cute.png",
       html_root_url    = "https://simnalamburt.github.io/bear")]

use std::path::Path;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;

/// Open a file from the 'tests/fixtures' directory, and return its content as a `String`
///
/// Example
/// --------
///
/// ```rust
/// use bear::fixture;
///
/// // Get a content of 'tests/fixtures/hello.txt'
/// let content = fixture("hello.txt");
///
/// /* Do whatever you want with it */
/// ```
pub fn fixture(filename: &str) -> String {
    let path = Path::new("tests").join("fixtures").join(filename);
    let file = File::open(&path).unwrap();
    let mut reader = BufReader::new(file);

    let mut ret = String::new();

    reader.read_to_string(&mut ret).unwrap();

    ret
}
<|endoftext|>


<commit_before>//! The `ipnetwork` crate provides a set of APIs to work with IP CIDRs in
//! Rust. Implementation for IPv4 is more or less stable, IPv6 implementation
//! is still WIP.
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![crate_type = "lib"]

use std::net::IpAddr;

mod ipv4;
mod ipv6;
mod common;

use std::str::FromStr;

pub use ipv4::{Ipv4Network, ipv4_mask_to_prefix};
pub use ipv6::{Ipv6Network, ipv6_mask_to_prefix};
pub use common::IpNetworkError;

/// Represents a generic network range. This type can have two variants:
/// the v4 and the v6 case.
#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub enum IpNetwork {
    V4(Ipv4Network),
    V6(Ipv6Network),
}

impl IpNetwork {
    /// Constructs a new `IpNetwork` from a given `IpAddr` and a prefix denoting the
    /// network size. If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
    /// will raise an `IpNetworkError::InvalidPrefix` error. Support for IPv6 is not
    /// complete yet.
    pub fn new(ip: IpAddr, prefix: u8) -> Result<IpNetwork, IpNetworkError> {
        match ip {
            IpAddr::V4(a) => Ok(IpNetwork::V4(Ipv4Network::new(a, prefix)?)),
            IpAddr::V6(a) => Ok(IpNetwork::V6(Ipv6Network::new(a, prefix)?)),
        }
    }

    /// Returns the IP part of a given `IpNetwork`
    ///
    /// # Example
    /// ```
    /// use std::net::{Ipv4Addr, Ipv6Addr};
    /// use ipnetwork::IpNetwork;
    ///
    /// assert_eq!(IpNetwork::V4("10.9.0.32/16".parse().unwrap()).ip(), "10.9.0.32".parse().unwrap());
    /// assert_eq!(IpNetwork::V6("ff01::0/32".parse().unwrap()).ip(), "ff01::0".parse().unwrap());
    /// ```
    pub fn ip(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.ip()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.ip()),
        }
    }

    /// Returns the prefix of the given `IpNetwork`
    ///
    /// # Example
    /// ```
    /// use ipnetwork::IpNetwork;
    ///
    /// assert_eq!(IpNetwork::V4("10.9.0.32/16".parse().unwrap()).prefix(), 16u8);
    /// assert_eq!(IpNetwork::V6("ff01::0/32".parse().unwrap()).prefix(), 32u8);
    /// ```
    pub fn prefix(&self) -> u8 {
        match *self {
            IpNetwork::V4(ref a) => a.prefix(),
            IpNetwork::V6(ref a) => a.prefix(),
        }
    }

    /// Returns the mask of the given `IpNetwork`
    ///
    /// # Example
    /// ```
    /// use ipnetwork::IpNetwork;
    ///
    /// assert_eq!(IpNetwork::V4("10.9.0.32/16".parse().unwrap()).mask(), 16u8);
    /// assert_eq!(IpNetwork::V6("ff01::0/32".parse().unwrap()).mask(), 32u8);
    ///```
    pub fn mask(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.mask()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.mask()),
        }
    }

    /// Returns true if the IP in this `IpNetwork` is a valid IPv4 address,
    /// false if it's a valid IPv6 address.
    ///
    /// # Example
    ///
    ///```
    /// use ipnetwork::IpNetwork;
    ///
    /// let v4: IpNetwork = IpNetwork::V4("10.9.0.32/16".parse().unwrap());
    /// assert_eq!(v4.is_ipv4(), true);
    /// assert_eq!(v4.is_ipv6(), false);
    ///```
    pub fn is_ipv4(&self) -> bool {
        match *self {
            IpNetwork::V4(_) => true,
            IpNetwork::V6(_) => false,
        }
    }

    /// Returns true if the IP in this `IpNetwork` is a valid IPv6 address,
    /// false if it's a valid IPv4 address.
    ///
    /// # Example
    ///
    ///```
    /// use ipnetwork::IpNetwork;
    ///
    /// let v6: IpNetwork = IpNetwork::V6("ff01::0/32".parse().unwrap());
    /// assert_eq!(v6.is_ipv6(), true);
    /// assert_eq!(v6.is_ipv4(), false);
    ///```
    pub fn is_ipv6(&self) -> bool {
        match *self {
            IpNetwork::V4(_) => false,
            IpNetwork::V6(_) => true,
        }
    }
}

/// Constructs a new `IpNetwork` from a given &str with a prefix denoting the
/// network size.  If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
/// will raise an `IpNetworkError::InvalidPrefix` error.
/// # Examples
///
/// ```
/// use std::net::Ipv4Addr;
/// use ipnetwork::Ipv4Network;
/// use ipnetwork::IpNetwork;
///
/// let expected = IpNetwork::V4(Ipv4Network::new(Ipv4Addr::new(10, 1, 9, 32), 16).unwrap());
/// let from_cidr: IpNetwork = "10.1.9.32/16".parse().unwrap();
/// assert_eq!(expected.ip(), from_cidr.ip());
/// assert_eq!(expected.prefix(), from_cidr.prefix());
impl FromStr for IpNetwork {
    type Err = IpNetworkError;
    fn from_str(s: &str) -> Result<IpNetwork, IpNetworkError> {
        let v4addr: Result<Ipv4Network, IpNetworkError> = s.parse();
        let v6addr: Result<Ipv6Network, IpNetworkError> = s.parse();

        if v4addr.is_ok() {
            Ok(IpNetwork::V4(v4addr.unwrap()))
        } else if v6addr.is_ok() {
            Ok(IpNetwork::V6(v6addr.unwrap()))
        } else {
            Err(IpNetworkError::InvalidAddr(s.to_string()))
        }
    }
}

impl From<Ipv4Network> for IpNetwork {
    fn from(v4: Ipv4Network) -> IpNetwork {
        IpNetwork::V4(v4)
    }
}

impl From<Ipv6Network> for IpNetwork {
    fn from(v6: Ipv6Network) -> IpNetwork {
        IpNetwork::V6(v6)
    }
}

/// Converts a `IpAddr` network mask into a prefix.
/// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`.
pub fn ip_mask_to_prefix(mask: IpAddr) -> Result<u8, IpNetworkError> {
    match mask {
        IpAddr::V4(mask) => ipv4_mask_to_prefix(mask),
        IpAddr::V6(mask) => ipv6_mask_to_prefix(mask),
    }
}
<commit_msg>Remove the offending doc test for now<commit_after>//! The `ipnetwork` crate provides a set of APIs to work with IP CIDRs in
//! Rust. Implementation for IPv4 is more or less stable, IPv6 implementation
//! is still WIP.
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![crate_type = "lib"]

use std::net::IpAddr;

mod ipv4;
mod ipv6;
mod common;

use std::str::FromStr;

pub use ipv4::{Ipv4Network, ipv4_mask_to_prefix};
pub use ipv6::{Ipv6Network, ipv6_mask_to_prefix};
pub use common::IpNetworkError;

/// Represents a generic network range. This type can have two variants:
/// the v4 and the v6 case.
#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub enum IpNetwork {
    V4(Ipv4Network),
    V6(Ipv6Network),
}

impl IpNetwork {
    /// Constructs a new `IpNetwork` from a given `IpAddr` and a prefix denoting the
    /// network size. If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
    /// will raise an `IpNetworkError::InvalidPrefix` error. Support for IPv6 is not
    /// complete yet.
    pub fn new(ip: IpAddr, prefix: u8) -> Result<IpNetwork, IpNetworkError> {
        match ip {
            IpAddr::V4(a) => Ok(IpNetwork::V4(Ipv4Network::new(a, prefix)?)),
            IpAddr::V6(a) => Ok(IpNetwork::V6(Ipv6Network::new(a, prefix)?)),
        }
    }

    /// Returns the IP part of a given `IpNetwork`
    pub fn ip(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.ip()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.ip()),
        }
    }

    /// Returns the prefix of the given `IpNetwork`
    ///
    /// # Example
    /// ```
    /// use ipnetwork::IpNetwork;
    ///
    /// assert_eq!(IpNetwork::V4("10.9.0.32/16".parse().unwrap()).prefix(), 16u8);
    /// assert_eq!(IpNetwork::V6("ff01::0/32".parse().unwrap()).prefix(), 32u8);
    /// ```
    pub fn prefix(&self) -> u8 {
        match *self {
            IpNetwork::V4(ref a) => a.prefix(),
            IpNetwork::V6(ref a) => a.prefix(),
        }
    }

    /// Returns the mask of the given `IpNetwork`
    ///
    /// # Example
    /// ```
    /// use ipnetwork::IpNetwork;
    ///
    /// assert_eq!(IpNetwork::V4("10.9.0.32/16".parse().unwrap()).mask(), 16u8);
    /// assert_eq!(IpNetwork::V6("ff01::0/32".parse().unwrap()).mask(), 32u8);
    ///```
    pub fn mask(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.mask()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.mask()),
        }
    }

    /// Returns true if the IP in this `IpNetwork` is a valid IPv4 address,
    /// false if it's a valid IPv6 address.
    ///
    /// # Example
    ///
    ///```
    /// use ipnetwork::IpNetwork;
    ///
    /// let v4: IpNetwork = IpNetwork::V4("10.9.0.32/16".parse().unwrap());
    /// assert_eq!(v4.is_ipv4(), true);
    /// assert_eq!(v4.is_ipv6(), false);
    ///```
    pub fn is_ipv4(&self) -> bool {
        match *self {
            IpNetwork::V4(_) => true,
            IpNetwork::V6(_) => false,
        }
    }

    /// Returns true if the IP in this `IpNetwork` is a valid IPv6 address,
    /// false if it's a valid IPv4 address.
    ///
    /// # Example
    ///
    ///```
    /// use ipnetwork::IpNetwork;
    ///
    /// let v6: IpNetwork = IpNetwork::V6("ff01::0/32".parse().unwrap());
    /// assert_eq!(v6.is_ipv6(), true);
    /// assert_eq!(v6.is_ipv4(), false);
    ///```
    pub fn is_ipv6(&self) -> bool {
        match *self {
            IpNetwork::V4(_) => false,
            IpNetwork::V6(_) => true,
        }
    }
}

/// Constructs a new `IpNetwork` from a given &str with a prefix denoting the
/// network size.  If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
/// will raise an `IpNetworkError::InvalidPrefix` error.
/// # Examples
///
/// ```
/// use std::net::Ipv4Addr;
/// use ipnetwork::Ipv4Network;
/// use ipnetwork::IpNetwork;
///
/// let expected = IpNetwork::V4(Ipv4Network::new(Ipv4Addr::new(10, 1, 9, 32), 16).unwrap());
/// let from_cidr: IpNetwork = "10.1.9.32/16".parse().unwrap();
/// assert_eq!(expected.ip(), from_cidr.ip());
/// assert_eq!(expected.prefix(), from_cidr.prefix());
impl FromStr for IpNetwork {
    type Err = IpNetworkError;
    fn from_str(s: &str) -> Result<IpNetwork, IpNetworkError> {
        let v4addr: Result<Ipv4Network, IpNetworkError> = s.parse();
        let v6addr: Result<Ipv6Network, IpNetworkError> = s.parse();

        if v4addr.is_ok() {
            Ok(IpNetwork::V4(v4addr.unwrap()))
        } else if v6addr.is_ok() {
            Ok(IpNetwork::V6(v6addr.unwrap()))
        } else {
            Err(IpNetworkError::InvalidAddr(s.to_string()))
        }
    }
}

impl From<Ipv4Network> for IpNetwork {
    fn from(v4: Ipv4Network) -> IpNetwork {
        IpNetwork::V4(v4)
    }
}

impl From<Ipv6Network> for IpNetwork {
    fn from(v6: Ipv6Network) -> IpNetwork {
        IpNetwork::V6(v6)
    }
}

/// Converts a `IpAddr` network mask into a prefix.
/// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`.
pub fn ip_mask_to_prefix(mask: IpAddr) -> Result<u8, IpNetworkError> {
    match mask {
        IpAddr::V4(mask) => ipv4_mask_to_prefix(mask),
        IpAddr::V6(mask) => ipv6_mask_to_prefix(mask),
    }
}
<|endoftext|>


<commit_before>//!
//! This is a base library for a simple software architecture designed to make it easy to create large
//! applications by combining small tools. The idea is nothing new: it's a core idea behind UNIX, component
//! libraries like COM+ and more recently microservices. This version is based around Rust and JSON, and it's
//! intended to strip the idea down to its bare essentials.
//!
//! When we learn to program, we're trained on small example programs because those are easy to write and
//! assess. Useful software, however, tends to be much larger and trying to apply the skills obtained through
//! writing smaller pieces of software has a tendency to result in a bit of a mess. A big issue is that the
//! high degree of coupling found in large pieces of software makes it difficult to change design descisions
//! made early on. This library provides a really very simple structure that can be used to build large
//! programs out of small parts.
//!
//! There are three parts to this architecture:
//!
//! ## Tools
//!
//! Tools are small programs that perform a single task. They take input (in the form of a JSON object) and
//! generate an output (also in the form of a JSON object). They can be invoked with no initialisation. In
//! general, they run immediately, perform their task on their input and return immediately.
//!
//! This design makes it easy to compose tools: feed the input of one into another. The input and output of
//! a tool is easy to understand and can be used to invoke it within the same process, within a different
//! process or even over the network. Tools are an excellent target for tests: for many tools, a test
//! requires no code: just the input JSON and the expected output JSON.
//!
//! Keeping tools to simple single purpose use cases means that any given tool should remain comparatively
//! simple. Making them composable makes it so that larger tools and applications can be built from smaller
//! ones. Having it so that they only talk in terms of concrete data means that it's easy to substitute one
//! tool for another even at runtime.
//!
//! ## The environment
//!
//! In order to invoke a tool, we need to be able to find it. This is what the environment is for: it takes
//! the name of a tool and returns an implementation.
//!
//! Using the environment to find tools make it easy to substitute one tool for another and reduces the effort
//! required to adapt a system to new circumstances.
//!
//! When tools are created, they are given a 'birth environment', where they can find other tools that they
//! may wish to invoke. This provides for static behaviour. Sometimes a tool may want more dynamic behaviour -
//! for instance to call another tool named in its input. To allow for this, tools are provided with their
//! environment when they are invoked.
//!
//! ## The automation layer
//!
//! Tools usually don't provide much of a feedback loop: they run, perform a single task, and then they stop.
//! To create an actual application, an 'automation layer' is used. This chains tools together and deals with
//! feedback. For a web app, this might be the HTML and Javascript that runs in the browser. For other apps,
//! this could be written in Rust or it could be written using a scripting language.
//!
//! With the right collection of tools, this layer can be kept comparatively simple - making it possible to
//! quickly create large applications.
//!

extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

pub mod tool;
pub mod environment;
pub mod basic;

pub use self::tool::*;
pub use self::environment::*;
<commit_msg>Update the docs and add some examples<commit_after>//!
//! This is a library for building small tools that can be composed into bigger pieces of software.
//!
//! There are three main concepts behind it:
//!
//! ## Tools
//!
//! Tools are simply small programs that perform a single task. They accept a single piece of input,
//! in the form of a JSON object and produce a single piece of output in the form of another JSON object.
//!
//! Tools can be chained together simply by passing the output of one into the input of another. As they
//! should be able to set themselves up, they are easy to test: no code is required in most cases, just
//! the input and the expected output. Using a strict data-only means of communication means that a tool
//! can effectively run anywhere, and using a loose, dynamic data type makes it easy to write tools that
//! can work together without needing a lot of extra knowledge.
//!
//! Tools can be created by implementing the `Tool` trait, but this library provides some convenience
//! functions for making new ones from Rust functions:
//!
//! ```
//! # #[macro_use] extern crate serde_json;
//! # #[macro_use] extern crate toolup;
//! # #[macro_use] extern crate serde;
//! # fn main() {
//! #
//! use toolup::*;
//! use toolup::basic::*;
//! use serde_json::*;
//!
//! let tool = make_pure_tool(|(x, y): (i32, i32)| x+y);
//! assert!(tool.invoke_json(json![ [ 1, 2 ] ], &EmptyEnvironment::new()) == Ok(json![ 3 ]));
//! # }
//! ```
//!
//! ## The environment
//!
//! In order to invoke a tool, we need to be able to find it. This is what the environment is for: it takes
//! the name of a tool and returns an implementation.
//!
//! Using the environment to find tools make it easy to substitute one tool for another and reduces the effort
//! required to adapt a system to new circumstances.
//!
//! When tools are created, they are given a 'birth environment', where they can find other tools that they
//! may wish to invoke. This provides for static behaviour. Sometimes a tool may want more dynamic behaviour -
//! for instance to call another tool named in its input. To allow for this, tools are provided with their
//! environment when they are invoked.
//!
//! The easiest environment to use is the dynamic environment, which allows for tools to be defined on the fly:
//!
//! ```
//! use toolup::basic::*;
//!
//! let env = DynamicEnvironment::new();
//! env.define("add", Box::new(make_pure_tool(|(x, y): (i32, i32)| x+y)));
//! ```
//!
//! There are some convenience functions to make tools from environments easier to work with:
//!
//! ```
//! # use toolup::basic::*;
//! #
//! # let env = DynamicEnvironment::new();
//! # env.define("add", Box::new(make_pure_tool(|(x, y): (i32, i32)| x+y)));
//! let typed_tool  = env.get_typed_tool("add").unwrap();
//! let result      = typed_tool.invoke((4, 5), &env);
//! assert!(result == Ok(9));
//! ```
//!
//! ## The orchestration layer
//!
//! Tools usually don't provide much of a feedback loop: they run, perform a single task, and then they stop.
//! To create an actual application, an 'orchestration layer' is used. This chains tools together and deals with
//! feedback. For a web app, this might be the HTML and Javascript that runs in the browser. For other apps,
//! this could be written in Rust or it could be written using a scripting language.
//!
//! With the right collection of tools, this layer can be kept comparatively simple - making it possible to
//! quickly create large applications.
//!

extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

pub mod tool;
pub mod environment;
pub mod basic;

pub use self::tool::*;
pub use self::environment::*;
<|endoftext|>


<commit_before>//
// yaml.rs
// Nothing to see here yet
//

#![crate_id="yaml"]

use std::iter::Iterator;
use std::option::Option;
use std::io::{IoResult, MemReader};
use std::borrow::Cow;
use self::Token::*;

/// A Yaml Tokenizer
///
/// A tokenizer takes a byte stream and produces a stream of Tokens
/// This shelters the parser from the complexity of dealing with raw bytes.
///
pub struct Tokenizer<'a> {
    reader: Box<Reader + 'a>,
    stack: Vec<u8>,
}

impl <'a>Tokenizer<'a> {

    /// Creates a new Tokenizer from a Reader
    pub fn new<T: Reader + 'a>(reader: Box<T>) -> Tokenizer<'a> {
        Tokenizer {
            reader: reader,
            stack: Vec::new(),
        }
    }

    fn read_char(&mut self) -> Option<char> {
        match self.reader.read_byte() {
            Ok(byte) => Some(byte as char),
            Err(_) => None,
        }
    }

    pub fn pop(&mut self) -> Option<char> {
        if(self.stack.len() == 0) {
            self.read_char()
        } else {
            match self.stack.pop() {
                Some(byte) => Some(byte as char),
                None => None,
            }
        }
    }

    pub fn next_token(&mut self) -> Option<Token> {
        match self.pop() {
            Some(character) => match character {
                '-' => {
                    if self.consume("--") {
                        Some(DocumentStart)
                    } else {
                        Some(SequenceEntry)
                    }
                },
                _ => {
                    self.stack.push(character as u8);
                    self.consume_scalar()
                },
            },
            None => None,
        }
    }

    fn consume_scalar(&mut self) -> Option<Token> {
        let mut eaten = Vec::new();
        loop {
            match self.pop() {
                Some(character) => match character {
                    'A'...'Z'|'a'...'z'|'0'...'9' => {
                        eaten.push(character as u8);
                    },
                    _ => {
                        self.stack.push(character as u8);
                        break;
                    },
                },
                None => {
                    break;
                }
            }
        }

        match String::from_utf8(eaten) {
            Ok(string) => Some(Scalar(string)),
            Err(_) => None,
        }
    }

    fn consume(&mut self, edible: &'static str) -> bool {
        let mut eaten = Vec::new();
        for expected in edible.chars() {
            let character = self.pop();
            if character.is_some() {
                let c = character.unwrap();
                eaten.push(c as u8);
                if c == expected {
                    continue;
                }
            }
            for ate in eaten.drain().rev() {
                self.stack.push(ate);
            }
            return false;
        }
        true
    }
}

/// All the types of tokens
///
/// Describes all of the token types described by the [Yaml 1.0 Spec](http://yaml.org/spec/1.0/)
///
#[derive(PartialEq, Debug)]
pub enum Token {

    /// `[`: the start of a _flow_ sequence
    /// `c-sequence-start` in the spec
    SequenceStart,

    /// `]`: the end of a _flow_ sequence
    /// `c-sequence-end` in the spec
    SequenceEnd,

    /// `{`: the end of a _flow_ mapping
    /// `c-mapping-start` in the spec
    MappingStart,

    /// `}`: the end of a _flow_ mapping
    /// `c-mapping-end` in the spec
    MappingEnd,

    /// `-`: indicates an entry in a sequence
    /// `c-sequence-entry` in the spec
    SequenceEntry,

    /// `:`: separates key from value in a mapping
    /// `c-mapping-entry` in the spec
    MappingSeparator,

    /// `,`: separates entries in _flow_ collections (mapping or sequence)
    /// `c-collect-entry` in the spec
    CollectionSeparator,

    /// `?`: indicates a complex key (e.g a non-scalar key)
    /// `c-complex-key` in the spec
    ComplexKey,

    /// `!`: indicates a tag property
    /// `c-tag` in the spec
    Tag,

    /// `&`: indicates an anchor property (e.g setting a variable)
    /// `c-anchor` in the spec
    Anchor(String),

    /// `*`: indicates an anchor property (e.g using a variable)
    /// `c-alias` in the spec
    Alias,

    /// `|`: indicates a literal value (not to be escaped)
    /// `c-literal` in the spec
    Literal,

    /// `>`: indicates a folded value (ignore line breaks)
    /// `c-folded` in the spec
    Folded,

    /// `'`: a single quoted scalar
    /// `c-single-quote` in the spec
    SingleQuote,

    /// `"`: a double quoted scalar
    /// `c-double-quote` in the spec
    DoubleQuote,

    /// `#`: a comment
    /// `c-throwaway`
    Comment,

    /// `%`: a directive (tags for the YAML parser)
    /// `c-directive` in the spec
    Directive,

    /// `@ | \``: reserved for future use?
    /// `c-reserved` in the spec
    Reserved,

    ///TODO Documentation
    ///
    DocumentStart,

    ///TODO: Documentation
    ///
    DocumentEnd,

    /// ``: a line break with no specific purpose
    LineBreakGeneric,

    /// ``
    LineBreak(LineBreakType),

    Other, // A temporary addition for unimplemented tokens
    Scalar(String),
    Eof,
}

#[derive(PartialEq, Copy, Debug)]
pub enum LineBreakType {
    Generic,
    LineSeparator,
    ParagraphSeparator
}

impl <'a>Iterator for Tokenizer<'a> {

    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.next_token()
    }
}

fn main() {
    let stream = "--hallo";
    let mut reader = MemReader::new(stream.bytes().collect());
    let mut tokenizer = Tokenizer::new(Box::new(reader));
    let tokens: Vec<Token> = tokenizer.collect();
    println!("{:?}", tokens);
}

<commit_msg>Change main to a test<commit_after>//
// yaml.rs
// Nothing to see here yet
//

#![crate_id="yaml"]

use std::iter::Iterator;
use std::option::Option;
use std::io::{IoResult, MemReader};
use std::borrow::Cow;
use self::Token::*;

/// A Yaml Tokenizer
///
/// A tokenizer takes a byte stream and produces a stream of Tokens
/// This shelters the parser from the complexity of dealing with raw bytes.
///
pub struct Tokenizer<'a> {
    reader: Box<Reader + 'a>,
    stack: Vec<u8>,
}

impl <'a>Tokenizer<'a> {

    /// Creates a new Tokenizer from a Reader
    pub fn new<T: Reader + 'a>(reader: Box<T>) -> Tokenizer<'a> {
        Tokenizer {
            reader: reader,
            stack: Vec::new(),
        }
    }

    fn read_char(&mut self) -> Option<char> {
        match self.reader.read_byte() {
            Ok(byte) => Some(byte as char),
            Err(_) => None,
        }
    }

    pub fn pop(&mut self) -> Option<char> {
        if(self.stack.len() == 0) {
            self.read_char()
        } else {
            match self.stack.pop() {
                Some(byte) => Some(byte as char),
                None => None,
            }
        }
    }

    pub fn next_token(&mut self) -> Option<Token> {
        match self.pop() {
            Some(character) => match character {
                '-' => {
                    if self.consume("--") {
                        Some(DocumentStart)
                    } else {
                        Some(SequenceEntry)
                    }
                },
                _ => {
                    self.stack.push(character as u8);
                    self.consume_scalar()
                },
            },
            None => None,
        }
    }

    fn consume_scalar(&mut self) -> Option<Token> {
        let mut eaten = Vec::new();
        loop {
            match self.pop() {
                Some(character) => match character {
                    'A'...'Z'|'a'...'z'|'0'...'9' => {
                        eaten.push(character as u8);
                    },
                    _ => {
                        self.stack.push(character as u8);
                        break;
                    },
                },
                None => {
                    break;
                }
            }
        }

        match String::from_utf8(eaten) {
            Ok(string) => Some(Scalar(string)),
            Err(_) => None,
        }
    }

    fn consume(&mut self, edible: &'static str) -> bool {
        let mut eaten = Vec::new();
        for expected in edible.chars() {
            let character = self.pop();
            if character.is_some() {
                let c = character.unwrap();
                eaten.push(c as u8);
                if c == expected {
                    continue;
                }
            }
            for ate in eaten.drain().rev() {
                self.stack.push(ate);
            }
            return false;
        }
        true
    }
}

/// All the types of tokens
///
/// Describes all of the token types described by the [Yaml 1.0 Spec](http://yaml.org/spec/1.0/)
///
#[derive(PartialEq, Debug)]
pub enum Token {

    /// `[`: the start of a _flow_ sequence
    /// `c-sequence-start` in the spec
    SequenceStart,

    /// `]`: the end of a _flow_ sequence
    /// `c-sequence-end` in the spec
    SequenceEnd,

    /// `{`: the end of a _flow_ mapping
    /// `c-mapping-start` in the spec
    MappingStart,

    /// `}`: the end of a _flow_ mapping
    /// `c-mapping-end` in the spec
    MappingEnd,

    /// `-`: indicates an entry in a sequence
    /// `c-sequence-entry` in the spec
    SequenceEntry,

    /// `:`: separates key from value in a mapping
    /// `c-mapping-entry` in the spec
    MappingSeparator,

    /// `,`: separates entries in _flow_ collections (mapping or sequence)
    /// `c-collect-entry` in the spec
    CollectionSeparator,

    /// `?`: indicates a complex key (e.g a non-scalar key)
    /// `c-complex-key` in the spec
    ComplexKey,

    /// `!`: indicates a tag property
    /// `c-tag` in the spec
    Tag,

    /// `&`: indicates an anchor property (e.g setting a variable)
    /// `c-anchor` in the spec
    Anchor(String),

    /// `*`: indicates an anchor property (e.g using a variable)
    /// `c-alias` in the spec
    Alias,

    /// `|`: indicates a literal value (not to be escaped)
    /// `c-literal` in the spec
    Literal,

    /// `>`: indicates a folded value (ignore line breaks)
    /// `c-folded` in the spec
    Folded,

    /// `'`: a single quoted scalar
    /// `c-single-quote` in the spec
    SingleQuote,

    /// `"`: a double quoted scalar
    /// `c-double-quote` in the spec
    DoubleQuote,

    /// `#`: a comment
    /// `c-throwaway`
    Comment,

    /// `%`: a directive (tags for the YAML parser)
    /// `c-directive` in the spec
    Directive,

    /// `@ | \``: reserved for future use?
    /// `c-reserved` in the spec
    Reserved,

    ///TODO Documentation
    ///
    DocumentStart,

    ///TODO: Documentation
    ///
    DocumentEnd,

    /// ``: a line break with no specific purpose
    LineBreakGeneric,

    /// ``
    LineBreak(LineBreakType),

    Other, // A temporary addition for unimplemented tokens
    Scalar(String),
    Eof,
}

#[derive(PartialEq, Copy, Debug)]
pub enum LineBreakType {
    Generic,
    LineSeparator,
    ParagraphSeparator
}

impl <'a>Iterator for Tokenizer<'a> {

    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.next_token()
    }
}

mod test {

    use std::io::MemReader;
    use super::{Tokenizer, Token};
    use super::Token::*;

    #[test]
    fn test_tokens() {
        let stream = "--hallo";
        let mut reader = MemReader::new(stream.bytes().collect());
        let mut tokenizer = Tokenizer::new(Box::new(reader));
        let tokens: Vec<Token> = tokenizer.collect();
        assert!(tokens == vec![SequenceEntry, SequenceEntry, Scalar("hallo".to_string())]);
    }
}
<|endoftext|>


<commit_before>//! # Rushell - shell script in rust.
//!
//! Rushell is a helper library for std::process::Command, which allows you to
//! write a shell script helps you to write a shell script in rust.
//!
//! ## cmd! macro
//!
//! You can easiliy create Command instance by using cmd! macro.
//!
//! ```
//! #[macro_use] extern crate shell;
//! fn main() {
//!   let command = cmd!("echo test");
//! }
//! ```
//!
//! You can specify an argument by using rust value as well.
//!
//! ```
//! #[macro_use] extern crate shell;
//! # fn main() {
//!   let name = "John";
//!   let command = cmd!("echo My name is {}.", name);
//! # }
//! ```
//!
//! ## Running command
//!
//! Rushell adds run() method to Command, which returns ShellResult.  Because
//! ShellResult regards exit code 0 is Ok and others are Err, you can easily
//! check an error with try operator (?).
//!
//!
//! ```
//! #[macro_use] extern crate shell;
//! # use shell::ShellResult;
//! # use shell::JobSpec;
//! fn my_shell_script() -> ShellResult {
//!   cmd!("echo test").run()?;
//!   cmd!("echo test").run()?;
//!   Ok(())
//! }
//! # fn main() {
//! #   my_shell_script().unwrap();
//! # }
//! ```
//!
//! ## Output string
//!
//! output_utf8() and error_utf8() can be used to run command and returns
//! String.
//!
//! ## Async control
//!
//! If you would like to run a command asynchronously, call async() instead of
//! run(). async() returns JobHandler which you can use to kill or wait the
//! running process. JobHandler automatically invokes wait() when it's dropped.
//! So you will not get a zombi process. You can explicitly detach a process
//! from job handler by calling detach() if you want to.
//!
//! ```test
//! #[macro_use] extern crate shell;
//! # use shell::JobSpec;
//! # use shell::ShellResult;
//! # fn main() {
//! # fn body() -> ShellResult {
//! let job = cmd!("sleep 100").spawn()?;
//! job.wait();
//! # Ok(())
//! # }
//! # body();
//! # }
//! ```
//!
//! # Subshell
//!
//! You can create a subshell which is a separated process to run shell
//! command by using subshell() function. subshell() returns a command so
//! that you can call run(), async() as well as a normal external command.
//!
//! ```
//! #[macro_use] extern crate shell;
//! # use shell::JobSpec;
//! # fn main() {
//! shell::subshell(|| {
//!     // Running in a separated process so changing current directory does
//!     // not affect a parante process.
//!     std::env::set_current_dir("./src")?;
//!     std::env::set_var("ENV_NAME", "HOGE");
//!     cmd!("echo test").run()?;
//!     Ok(())
//! }).run().unwrap();
//! # }
//! ```
//!

#[macro_use] extern crate lazy_static;
#[macro_use] extern crate nom;
extern crate libc;
extern crate errno;

mod signal_handler;
#[macro_use] pub mod command;
pub mod result;

pub use result::check_errno;
use result::ShellError;
use result::ShellResult;
use result::ShellResultExt;
use signal_handler::SIGNAL_HANDLER;
use std::panic;
use std::sync::Mutex;

pub fn subshell<F>(func: F) ->
        SubShell where F: Fn() -> ShellResult + 'static {
    SubShell {
        func: Box::new(func),
        setpgid: false
    }
}

/// Something which can be used as a command
pub trait JobSpec where Self: Sized {
    fn exec(self) -> !;
    fn setpgid(self) -> Self;
    fn getpgid(&self) -> bool;

    fn spawn(self) -> Result<JobHandle, ShellError> {
        let pgid = self.getpgid();
        self.spawn_internal(pgid)
    }

    fn spawn_internal(self, setpgid: bool) -> Result<JobHandle, ShellError> {
        let pid = unsafe {
            let mut signal_handler = SIGNAL_HANDLER.lock().unwrap();
            let pid = check_errno("fork", libc::fork())?;
            // Call setpgid in both processes to avoid race.
            if setpgid {
                check_errno("setpgid", libc::setpgid(pid, 0)).unwrap();
            }
            if pid != 0 {
                signal_handler.add_pid(pid);
            } else {
                signal_handler.clear();
            }
            pid
        };
        unsafe {
            if pid == 0 {
                let mutex = Mutex::new(self);
                panic::catch_unwind(move || {
                    let lock = mutex.into_inner().unwrap();
                    lock.exec()
                }).is_ok();
                std::process::exit(101);
                // Process replaced
            } else {
                libc::kill(pid, libc::SIGCONT);
            }
        }
        // signal_handler.add_pid(pid);
        Ok(JobHandle { pid: pid, setpgid: setpgid })
    }

    fn run(self) -> ShellResult {
        let pgid = self.getpgid();
        self.spawn_internal(pgid)?.wait()
    }
}

/// Block
/// TODO: Change FnMut to FnOnce after fnbox is resolved.
pub struct SubShell {
    func: Box<Fn() -> ShellResult + 'static>,
    setpgid: bool
}

impl JobSpec for SubShell {
    fn exec(mut self) -> ! {
        (self.func)().unwrap();
        std::process::exit(0);
    }

    fn setpgid(mut self) -> Self {
        self.setpgid = true;
        self
    }

    fn getpgid(&self) -> bool {
        return self.setpgid;
    }
}

/// Job which is a process leader.
pub struct JobHandle { pid: i32, setpgid: bool }

impl JobHandle {
    /// Sends a SIGTERM to a process group, then wait a process leader.
    pub fn terminate(self) -> ShellResult {
        assert_ne!(self.pid, 0);
        unsafe {
            let pid = if self.setpgid {
                -self.pid
            } else {
                self.pid
            };
            check_errno("kill", libc::kill(pid, libc::SIGTERM))?;
            match self.wait() {
                Ok(()) | Err(ShellError::Code(_))
                    | Err(ShellError::Signaled(_)) => Ok(()),
                err => err
            }
        }
    }

    /// Wait for termination of the process.
    pub fn wait(mut self) -> ShellResult {
        self.wait_mut()
    }

    fn wait_mut(&mut self) -> ShellResult {
        if self.pid == 0 {
            return Ok(());
        }
        let pid = self.pid;
        self.pid = 0;
        loop {
            unsafe {
                let mut status: libc::c_int = 0;
                check_errno("waitpid", libc::waitpid(
                        pid, &mut status as *mut i32, 0))?;

                if libc::WIFEXITED(status) {
                    let code = libc::WEXITSTATUS(status);
                    if code == 0 {
                        return Ok(());
                    } else {
                        return Err(ShellError::Code(code as u8));
                    }
                } else if libc::WIFSIGNALED(status) {
                    let signal = libc::WTERMSIG(status);
                    return Err(ShellError::Signaled(signal));
                }
            }
        }
    }
}

impl Drop for JobHandle {
    fn drop(&mut self) {
        self.wait_mut().unwrap();
    }
}

pub fn try<F>(f: F) -> ShellResult where F: FnOnce() -> ShellResult {
    f()
}

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

    #[test]
    fn test_command_run() {
        ::try(|| {
            cmd!("test 0 = 0").run()?;
            Ok(())
        }).unwrap();
    }

    #[test]
    fn test_subshell_terminate() {
        ::try(|| {
            let job = ::subshell(|| {
                ::subshell(|| {
                    ::std::thread::sleep(::std::time::Duration::from_secs(10));
                    Ok(())
                }).spawn()?;
                Ok(())
            }).spawn()?;
            ::std::thread::sleep(::std::time::Duration::from_secs(1));
            job.terminate()?;
            Ok(())
        }).unwrap();
    }
}

<commit_msg>Fix doc test<commit_after>//! # Rushell - shell script in rust.
//!
//! Rushell is a helper library for std::process::Command, which allows you to
//! write a shell script helps you to write a shell script in rust.
//!
//! ## cmd! macro
//!
//! You can easiliy create Command instance by using cmd! macro.
//!
//! ```
//! #[macro_use] extern crate shell;
//! fn main() {
//!   let command = cmd!("echo test");
//! }
//! ```
//!
//! You can specify an argument by using rust value as well.
//!
//! ```
//! #[macro_use] extern crate shell;
//! # fn main() {
//!   let name = "John";
//!   let command = cmd!("echo My name is {}.", name);
//! # }
//! ```
//!
//! ## Running command
//!
//! Rushell adds run() method to Command, which returns ShellResult.  Because
//! ShellResult regards exit code 0 is Ok and others are Err, you can easily
//! check an error with try operator (?).
//!
//!
//! ```
//! #[macro_use] extern crate shell;
//! # use shell::result::ShellResult;
//! # use shell::JobSpec;
//! fn my_shell_script() -> ShellResult {
//!   cmd!("echo test").run()?;
//!   cmd!("echo test").run()?;
//!   Ok(())
//! }
//! # fn main() {
//! #   my_shell_script().unwrap();
//! # }
//! ```
//!
//! ## Output string
//!
//! output_utf8() and error_utf8() can be used to run command and returns
//! String.
//!
//! ## Async control
//!
//! If you would like to run a command asynchronously, call async() instead of
//! run(). async() returns JobHandler which you can use to kill or wait the
//! running process. JobHandler automatically invokes wait() when it's dropped.
//! So you will not get a zombi process. You can explicitly detach a process
//! from job handler by calling detach() if you want to.
//!
//! ```test
//! #[macro_use] extern crate shell;
//! # use shell::JobSpec;
//! # use shell::result::ShellResult;
//! # fn main() {
//! # fn body() -> ShellResult {
//! let job = cmd!("sleep 100").spawn()?;
//! job.wait();
//! # Ok(())
//! # }
//! # body();
//! # }
//! ```
//!
//! # Subshell
//!
//! You can create a subshell which is a separated process to run shell
//! command by using subshell() function. subshell() returns a command so
//! that you can call run(), async() as well as a normal external command.
//!
//! ```
//! #[macro_use] extern crate shell;
//! # use shell::JobSpec;
//! # fn main() {
//! shell::subshell(|| {
//!     // Running in a separated process so changing current directory does
//!     // not affect a parante process.
//!     std::env::set_current_dir("./src")?;
//!     std::env::set_var("ENV_NAME", "HOGE");
//!     cmd!("echo test").run()?;
//!     Ok(())
//! }).run().unwrap();
//! # }
//! ```
//!

#[macro_use] extern crate lazy_static;
#[macro_use] extern crate nom;
extern crate libc;
extern crate errno;

mod signal_handler;
#[macro_use] pub mod command;
pub mod result;

pub use result::check_errno;
use result::ShellError;
use result::ShellResult;
use result::ShellResultExt;
use signal_handler::SIGNAL_HANDLER;
use std::panic;
use std::sync::Mutex;

pub fn subshell<F>(func: F) ->
        SubShell where F: Fn() -> ShellResult + 'static {
    SubShell {
        func: Box::new(func),
        setpgid: false
    }
}

/// Something which can be used as a command
pub trait JobSpec where Self: Sized {
    fn exec(self) -> !;
    fn setpgid(self) -> Self;
    fn getpgid(&self) -> bool;

    fn spawn(self) -> Result<JobHandle, ShellError> {
        let pgid = self.getpgid();
        self.spawn_internal(pgid)
    }

    fn spawn_internal(self, setpgid: bool) -> Result<JobHandle, ShellError> {
        let pid = unsafe {
            let mut signal_handler = SIGNAL_HANDLER.lock().unwrap();
            let pid = check_errno("fork", libc::fork())?;
            // Call setpgid in both processes to avoid race.
            if setpgid {
                check_errno("setpgid", libc::setpgid(pid, 0)).unwrap();
            }
            if pid != 0 {
                signal_handler.add_pid(pid);
            } else {
                signal_handler.clear();
            }
            pid
        };
        unsafe {
            if pid == 0 {
                let mutex = Mutex::new(self);
                panic::catch_unwind(move || {
                    let lock = mutex.into_inner().unwrap();
                    lock.exec()
                }).is_ok();
                std::process::exit(101);
                // Process replaced
            } else {
                libc::kill(pid, libc::SIGCONT);
            }
        }
        // signal_handler.add_pid(pid);
        Ok(JobHandle { pid: pid, setpgid: setpgid })
    }

    fn run(self) -> ShellResult {
        let pgid = self.getpgid();
        self.spawn_internal(pgid)?.wait()
    }
}

/// Block
/// TODO: Change FnMut to FnOnce after fnbox is resolved.
pub struct SubShell {
    func: Box<Fn() -> ShellResult + 'static>,
    setpgid: bool
}

impl JobSpec for SubShell {
    fn exec(mut self) -> ! {
        (self.func)().unwrap();
        std::process::exit(0);
    }

    fn setpgid(mut self) -> Self {
        self.setpgid = true;
        self
    }

    fn getpgid(&self) -> bool {
        return self.setpgid;
    }
}

/// Job which is a process leader.
pub struct JobHandle { pid: i32, setpgid: bool }

impl JobHandle {
    /// Sends a SIGTERM to a process group, then wait a process leader.
    pub fn terminate(self) -> ShellResult {
        assert_ne!(self.pid, 0);
        unsafe {
            let pid = if self.setpgid {
                -self.pid
            } else {
                self.pid
            };
            check_errno("kill", libc::kill(pid, libc::SIGTERM))?;
            match self.wait() {
                Ok(()) | Err(ShellError::Code(_))
                    | Err(ShellError::Signaled(_)) => Ok(()),
                err => err
            }
        }
    }

    /// Wait for termination of the process.
    pub fn wait(mut self) -> ShellResult {
        self.wait_mut()
    }

    fn wait_mut(&mut self) -> ShellResult {
        if self.pid == 0 {
            return Ok(());
        }
        let pid = self.pid;
        self.pid = 0;
        loop {
            unsafe {
                let mut status: libc::c_int = 0;
                check_errno("waitpid", libc::waitpid(
                        pid, &mut status as *mut i32, 0))?;

                if libc::WIFEXITED(status) {
                    let code = libc::WEXITSTATUS(status);
                    if code == 0 {
                        return Ok(());
                    } else {
                        return Err(ShellError::Code(code as u8));
                    }
                } else if libc::WIFSIGNALED(status) {
                    let signal = libc::WTERMSIG(status);
                    return Err(ShellError::Signaled(signal));
                }
            }
        }
    }
}

impl Drop for JobHandle {
    fn drop(&mut self) {
        self.wait_mut().unwrap();
    }
}

pub fn try<F>(f: F) -> ShellResult where F: FnOnce() -> ShellResult {
    f()
}

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

    #[test]
    fn test_command_run() {
        ::try(|| {
            cmd!("test 0 = 0").run()?;
            Ok(())
        }).unwrap();
    }

    #[test]
    fn test_subshell_terminate() {
        ::try(|| {
            let job = ::subshell(|| {
                ::subshell(|| {
                    ::std::thread::sleep(::std::time::Duration::from_secs(10));
                    Ok(())
                }).spawn()?;
                Ok(())
            }).spawn()?;
            ::std::thread::sleep(::std::time::Duration::from_secs(1));
            job.terminate()?;
            Ok(())
        }).unwrap();
    }
}

<|endoftext|>


<commit_before>
extern crate xml;

use std::convert::AsRef;
use std::path::Path;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;

use xml::reader::EventReader;
use xml::reader::events::XmlEvent;

#[derive(Debug)]
pub struct Element {
    pub name: String,
    pub attributes: HashMap<String, String>,
    pub children: Vec<Element>,
    pub text: Option<String>
}

fn build<B: Read>(reader: &mut EventReader<B>, mut elem: Element) -> Element {

    loop {
        match reader.next() {
            XmlEvent::EndElement{ref name} if name.local_name == elem.name => { return elem; }
            XmlEvent::StartElement{name, attributes, namespace} => {
                let mut attr_map = HashMap::new();
                for attr in attributes { attr_map.insert(attr.name.local_name, attr.value); }
                let new_elem = Element{name: name.local_name, attributes: attr_map, children: Vec::new(), text: None};
                elem.children.push(build(reader, new_elem));
            }
            XmlEvent::Characters(s) => { elem.text = Some(s); }
            XmlEvent::Whitespace(..) => (),
            XmlEvent::CData(s) => { elem.text = Some(s) }
            x => {panic!("Unsure what to do with {:?}", x)}
        }
    }

    elem
}

pub fn parse<P: AsRef<Path>>(p: P) -> Element {
    let f = File::open(p).unwrap();
    let mut reader = EventReader::new(f);

    loop {
        match reader.next() {
            XmlEvent::StartElement{name, attributes, namespace} => {
                let mut attr_map = HashMap::new();
                for attr in attributes { attr_map.insert(attr.name.local_name, attr.value); }

                let root = Element{name: name.local_name, attributes: attr_map, children: Vec::new(), text: None};
                return build(&mut reader, root);
            }
            XmlEvent::EndDocument => break,
            XmlEvent::Error(e) => panic!("{:?}", e),
            _ => ()

        }
    }
    panic!("Error")

}

<commit_msg>Added lame documentation<commit_after>//! A simple library for parsing an XML file into an in-memory tree structure
//!
//! Not well tested, and not recommended for large XML files
extern crate xml;

use std::convert::AsRef;
use std::path::Path;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;

use xml::reader::EventReader;
use xml::reader::events::XmlEvent;

#[derive(Debug)]
pub struct Element {
    /// The name of the Element.  Does not include any namespace info
    pub name: String,

    /// The Element attributes
    pub attributes: HashMap<String, String>,

    /// Children
    pub children: Vec<Element>,

    /// The text data for this element
    pub text: Option<String>
}

fn build<B: Read>(reader: &mut EventReader<B>, mut elem: Element) -> Element {

    loop {
        match reader.next() {
            XmlEvent::EndElement{ref name} if name.local_name == elem.name => { return elem; }
            XmlEvent::StartElement{name, attributes, namespace} => {
                let mut attr_map = HashMap::new();
                for attr in attributes { attr_map.insert(attr.name.local_name, attr.value); }
                let new_elem = Element{name: name.local_name, attributes: attr_map, children: Vec::new(), text: None};
                elem.children.push(build(reader, new_elem));
            }
            XmlEvent::Characters(s) => { elem.text = Some(s); }
            XmlEvent::Whitespace(..) => (),
            XmlEvent::CData(s) => { elem.text = Some(s) }
            x => {panic!("Unsure what to do with {:?}", x)}
        }
    }

    elem
}

/// Parses a file into an Element
///
/// # Panics
///
/// Panics on error or other unhandled condition
pub fn parse<P: AsRef<Path>>(p: P) -> Element {
    let f = File::open(p).unwrap();
    let mut reader = EventReader::new(f);

    loop {
        match reader.next() {
            XmlEvent::StartElement{name, attributes, namespace} => {
                let mut attr_map = HashMap::new();
                for attr in attributes { attr_map.insert(attr.name.local_name, attr.value); }

                let root = Element{name: name.local_name, attributes: attr_map, children: Vec::new(), text: None};
                return build(&mut reader, root);
            }
            XmlEvent::EndDocument => break,
            XmlEvent::Error(e) => panic!("{:?}", e),
            _ => ()

        }
    }
    panic!("Error")

}
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(core)]
#![feature(plugin)]
#![plugin(regex_macros)]
extern crate "rustc-serialize" as serialize;

extern crate regex_macros;
extern crate regex;

extern crate collections;
extern crate url;

pub use parser::{parse, ParseResult, ParseError, ParseErrorKind};

mod merge;
mod mutable_json;
mod helpers;
mod parser;

<commit_msg>refactor(lib): rustup; fix warning<commit_after>#![feature(collections)]
#![feature(core)]
#![feature(plugin)]
#![plugin(regex_macros)]
extern crate "rustc-serialize" as serialize;

extern crate regex;

extern crate collections;
extern crate url;

pub use parser::{parse, ParseResult, ParseError, ParseErrorKind};

mod merge;
mod mutable_json;
mod helpers;
mod parser;

<|endoftext|>