<commit_before>use anyhow::{anyhow, Result};
use std::collections::HashMap;

#[derive(Debug, Clone)]
pub struct Graph {
    adjacencies: HashMap<String, Vec<String>>,
}

pub fn parse(input: &str) -> Result<Graph> {
    let mut adjacencies: HashMap<String, Vec<String>> = HashMap::new();
    for line in input.lines().map(|l| l.trim()).filter(|l| !l.is_empty()) {
        if let Some((a, b)) = line.split_once('-') {
            adjacencies
                .entry(a.to_string())
                .or_default()
                .push(b.to_string());
            adjacencies
                .entry(b.to_string())
                .or_default()
                .push(a.to_string());
        } else {
            return Err(anyhow!("line \"{}\" did not contain a dash", line));
        }
    }
    Ok(Graph { adjacencies })
}

fn paths(start: &str, end: &str, graph: &Graph, path_so_far: &[String]) -> Vec<Vec<String>> {
    if start == end {
        return vec![vec![end.to_string()]];
    }
    let mut paths_found = vec![];
    let mut updated_path = path_so_far.to_vec();
    updated_path.push(start.to_string());
    for neighbor in graph.adjacencies[start].iter() {
        let is_small = neighbor.chars().all(|c| c.is_ascii_lowercase());
        if is_small && path_so_far.contains(neighbor) {
            continue;
        }
        for found in paths(neighbor, end, graph, &updated_path) {
            paths_found.push(
                std::iter::once(start.to_owned())
                    .chain(found.into_iter())
                    .collect(),
            )
        }
    }
    paths_found
}

fn paths_2(
    start: &str,
    end: &str,
    graph: &Graph,
    path_so_far: &[String],
    revisited: bool,
) -> Vec<Vec<String>> {
    if start == end {
        return vec![vec![end.to_string()]];
    }
    let mut paths_found = vec![];
    let mut updated_path = path_so_far.to_vec();
    updated_path.push(start.to_string());
    for neighbor in graph.adjacencies[start].iter() {
        let mut revisited = revisited; // this one applies for this neighbor and child calls
        let is_small = neighbor.chars().all(|c| c.is_ascii_lowercase());
        if neighbor == "start" {
            continue;
        }
        if is_small && path_so_far.contains(neighbor) {
            if revisited {
                continue;
            } else {
                revisited = true;
            }
        }
        for found in paths_2(neighbor, end, graph, &updated_path, revisited) {
            paths_found.push(
                std::iter::once(start.to_owned())
                    .chain(found.into_iter())
                    .collect(),
            )
        }
    }
    paths_found
}

pub fn part1(input: &Graph) -> usize {
    paths("start", "end", input, &[]).len()
}

pub fn part2(input: &Graph) -> usize {
    paths_2("start", "end", input, &[], false).len()
}

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

    const A: &str = r"
start-A
start-b
A-c
A-b
b-d
A-end
b-end";

    const B: &str = r"
dc-end
HN-start
start-kj
dc-start
dc-HN
LN-dc
HN-end
kj-sa
kj-HN
kj-dc";

    const C: &str = r"
fs-end
he-DX
fs-he
start-DX
pj-DX
end-zg
zg-sl
zg-pj
pj-he
RW-he
fs-DX
pj-RW
zg-RW
start-pj
he-WI
zg-he
pj-fs
start-RW
";

    #[test]
    fn test_part1() {
        assert_eq!(part1(&parse(A).unwrap()), 10);
        assert_eq!(part1(&parse(B).unwrap()), 19);
        assert_eq!(part1(&parse(C).unwrap()), 226);
    }

    #[test]
    fn test_part2() {
        assert_eq!(part2(&parse(A).unwrap()), 36);
        assert_eq!(part2(&parse(B).unwrap()), 103);
        assert_eq!(part2(&parse(C).unwrap()), 3509);
    }
}
<commit_msg>2021 day 12 optimization<commit_after>use anyhow::{anyhow, Result};
use std::collections::HashMap;

#[derive(Debug, Clone)]
pub struct Graph {
    adjacencies: Vec<Vec<usize>>,  // idx -> list of neighboring idxs
    smalls: Vec<usize>,            // index of small caves
    names: HashMap<String, usize>, // name -> idx
}

pub fn parse(input: &str) -> Result<Graph> {
    let mut adjacencies = Vec::new();
    let mut smalls = Vec::new();
    let mut names = HashMap::new();
    for line in input.lines().map(|l| l.trim()).filter(|l| !l.is_empty()) {
        if let Some((a, b)) = line.split_once('-') {
            let a_idx = *names.entry(a.to_string()).or_insert_with(|| {
                adjacencies.push(vec![]);
                let idx = adjacencies.len() - 1;
                if a.chars().all(|c| c.is_ascii_lowercase()) {
                    smalls.push(idx);
                }
                idx
            });
            let b_idx = *names.entry(b.to_string()).or_insert_with(|| {
                adjacencies.push(vec![]);
                let idx = adjacencies.len() - 1;
                if b.chars().all(|c| c.is_ascii_lowercase()) {
                    smalls.push(idx);
                }
                idx
            });
            adjacencies[a_idx].push(b_idx);
            adjacencies[b_idx].push(a_idx);
        } else {
            return Err(anyhow!("line \"{}\" did not contain a dash", line));
        }
    }
    Ok(Graph {
        adjacencies,
        smalls,
        names,
    })
}

fn part1_helper(start: usize, end: usize, graph: &Graph, path_so_far: &mut Vec<usize>) -> usize {
    if start == end {
        return 1;
    }
    let mut paths_found = 0;
    path_so_far.push(start);
    for neighbor in graph.adjacencies[start].iter().copied() {
        if graph.smalls.contains(&neighbor) && path_so_far.contains(&neighbor) {
            continue;
        }
        paths_found += part1_helper(neighbor, end, graph, path_so_far);
    }
    path_so_far.pop();
    paths_found
}

fn part2_helper(
    start: usize,
    end: usize,
    graph: &Graph,
    path_so_far: &mut Vec<usize>,
    revisited: bool,
) -> usize {
    if start == end {
        return 1;
    }
    let mut paths_found = 0;
    path_so_far.push(start);
    let origin = graph.names["start"];
    for neighbor in graph.adjacencies[start].iter().copied() {
        if neighbor == origin {
            continue;
        }
        let mut revisited = revisited; // this one applies for this neighbor and child calls
        if graph.smalls.contains(&neighbor) && path_so_far.contains(&neighbor) {
            if revisited {
                continue;
            } else {
                revisited = true;
            }
        }
        paths_found += part2_helper(neighbor, end, graph, path_so_far, revisited);
    }
    path_so_far.pop();
    paths_found
}

pub fn part1(input: &Graph) -> usize {
    part1_helper(input.names["start"], input.names["end"], input, &mut vec![])
}

pub fn part2(input: &Graph) -> usize {
    part2_helper(
        input.names["start"],
        input.names["end"],
        input,
        &mut vec![],
        false,
    )
}

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

    const A: &str = r"
start-A
start-b
A-c
A-b
b-d
A-end
b-end";

    const B: &str = r"
dc-end
HN-start
start-kj
dc-start
dc-HN
LN-dc
HN-end
kj-sa
kj-HN
kj-dc";

    const C: &str = r"
fs-end
he-DX
fs-he
start-DX
pj-DX
end-zg
zg-sl
zg-pj
pj-he
RW-he
fs-DX
pj-RW
zg-RW
start-pj
he-WI
zg-he
pj-fs
start-RW
";

    #[test]
    fn test_part1() {
        assert_eq!(part1(&parse(A).unwrap()), 10);
        assert_eq!(part1(&parse(B).unwrap()), 19);
        assert_eq!(part1(&parse(C).unwrap()), 226);
    }

    #[test]
    fn test_part2() {
        assert_eq!(part2(&parse(A).unwrap()), 36);
        assert_eq!(part2(&parse(B).unwrap()), 103);
        assert_eq!(part2(&parse(C).unwrap()), 3509);
    }
}
<|endoftext|>


<commit_before>/*
 * A basic EBML parser for Rust. Gives methods for both approaches; full parsing
 * of an EBML file in-memory or incremental sequential parsing of nodes for
 * environments that are more memory-constrained.
 *
 * The full parser allows you to get all sub-elements of a node in one call,
 * because each node has a reference to the data it contains.
 *
 * The PartialElement only contains a reference to the data source, not the data
 * itself. So if the data source is a file the full parser will load the whole
 * file to memory, while the partial parser will only load at most one leaf
 * node's value plus its id and size.
 *
 * The partial parser stores the offset of each node in the input stream, which
 * is then used to jump to the node's data in the stream. This may cause the
 * partial parser to do more random seeking.
 */

use std::io::Memreader;
use std::time::Timespec;

pub mod rebml {
	// Error struct to give information when something goes wrong
	struct ParseError {
		error: String,
	}

	// Element for a full reader
	struct Element {
		id: u32,
		size: u64,
		data: &[u8]
	}

	// Element for an incremental reader
	struct PartialElement {
		id: u32,
		size: u64
	}

	enum Value {
		SubElement(Element),
		Uint(u64),
		Int(i64),
		Str(String),
		Date(Timespec),
		Bin(&[u8]),
		Err(EbmlError)
	}

	fn full_parse(input: Reader) -> Result<Element> {
		let mut ele: Element;
		// Attempt to read root element
		match (input.read_be_u64()) {
			Ok(val) => ele.id = val,
			Err(err) => println!("Failed to get root element"),
		}
	}

	fn incremental_parse(input: Reader) -> Result<PartialElement> {
		let mut ele: PartialElement;
	}

	impl Element {
		// TODO: method to return vec of sub-elements
		// TODO: get properties
	}

	impl PartialElement {
		// TODO: method to read sub/adjacent PartialElement
		// TODO: get properties
	}
}
<commit_msg>Fleshed out thedifferent strategies for EBML parsing a bit.<commit_after>/*
 * A basic EBML parser for Rust. Gives methods for both approaches; full parsing
 * of an EBML file in-memory or incremental sequential parsing of nodes for
 * environments that are more memory-constrained.
 *
 * The full parser allows you to get all sub-elements of a node in one call,
 * because each node has a reference to the data it contains. All of the data is
 * loaded into memory when the root node is parsed.
 *
 * The PartialElement only reads the data it needs to get the header of any
 * single element. So if the data source is a file the full parser will load the
 * whole file to memory, while the partial parser will only load at most one leaf
 * node's value plus its id and size.
 *
 * The partial parser stores the offset of each node in the input stream, which
 * is then used to jump to the node's data in the stream. This may cause the
 * partial parser to do more random seeking.
 */

extern crate time;
//use std::io::Memreader;
//use time::Timespec;
use std::io::IoResult;

pub mod rebml {
	// Element for an incremental reader
	struct ElementHeader {
		id: u32,
		size: u64
	}

	/*// Element for a full reader
	struct Element {
		header: ElementHeader,
		data: &[u8]
	}*/

	enum Value {
		SubElement(ElementHeader),
		Uint(u64),
		Int(i64),
		Str(String),
		Date(time::Timespec),
		Bin(&[u8]),
		Nil, // Empty element
	}

	enum Type {

	}

	/*fn full_parse(input: &Reader) -> IoResult<Element> {
		let mut ele: Element;
		// Attempt to read root element
		match (input.read_be_u64()) {
			Ok(val) => ele.header.id = val,
			Error(err) => return Error(err),
		}
	}*/

	fn partial_parse(input: &Reader) -> IoResult<ElementHeader> {
	}

	/*impl Element {
		fn sub_elements() -> IoResult<Vec<Element>> {
		}

		fn value() -> IoResult<Option<Value>> {

		}
		// TODO: get properties
	}*/

	impl ElementHeader {
		/*
		 * Get next the next node after this one in the given input stream.
		 */
		fn next(input: &Reader) -> IoResult<ElementHeader> {
		}

		/*
		 * Get the value of this node
		 */
		fn value(input: &Reader) -> IoResult<Value> {
		}
		// TODO: method to read sub/adjacent PartialElement
		// TODO: get properties
	}
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;
use nom::{IResult, space, multispace, Needed, Err};
use nom::IResult::*;
use std::str;
use std::collections::HashMap;

fn version_number(input: &[u8]) -> IResult<&[u8], &[u8]> {
    for (idx, chr) in input.iter().enumerate() {
        match *chr {
            46 | 48...57  => continue,
            _ => return IResult::Done(&input[idx..], &input[..idx]),
        }
    }
    IResult::Incomplete(Needed::Size(1))
}

fn just_about_everything(input: &[u8]) -> IResult<&[u8], &[u8]> {
    for (idx, chr) in input.iter().enumerate() {
        match *chr {
            32...126 => continue,
            _ => return IResult::Done(&input[idx..], &input[..idx]),
        }
    }
    IResult::Incomplete(Needed::Size(1))
}
fn token(input: &[u8]) -> IResult<&[u8], &[u8]> {
    for (idx, chr) in input.iter().enumerate() {
        match *chr {
            33 | 35...39 | 42 | 43 | 45 | 48...57 | 65...90 | 94...122 | 124 => continue,
            _ => return IResult::Done(&input[idx..], &input[..idx]),
        }
    }
    IResult::Incomplete(Needed::Size(1))
}
named!(init_line <&[u8], (&str, &str)>,
    chain!(
        multispace?                  ~
        tag!("WARC")                ~
        tag!("/")                   ~
        space?                      ~
        version: map_res!(version_number, str::from_utf8)~
        tag!("\r")?                 ~
        tag!("\n")                  ,
        || {("WARCVERSION", version)}
        )
    );
named!(header_match <&[u8], (&str, &str)>,
    chain!(
        name: map_res!(token, str::from_utf8)~
        space?                      ~
        tag!(":")                   ~
        space?                      ~
        value: map_res!(just_about_everything, str::from_utf8)~
        tag!("\r")?                 ~
        tag!("\n")                  ,
        || {(name, value)}
        )
    );

named!(header_aggregator<&[u8], Vec<(&str,&str)> >, many1!(header_match));

named!(warc_header<&[u8], ((&str, &str), Vec<(&str,&str)>) >,
chain!(
    version: init_line              ~
    headers: header_aggregator      ,
    move ||{(version, headers)}
    )
);

pub fn record(input: &[u8]) -> IResult<&[u8], HashMap<&str,&str>>{
    let mut h: HashMap<&str,  &str> = HashMap::new();
    match warc_header(input) {
        IResult::Done(mut i, tuple_vec) => {
            let (name, version) = tuple_vec.0;
            h.insert(name, version);
            let headers =  tuple_vec.1;
            for &(k,ref v) in headers.iter() {
                h.insert(k, v.clone());
            }
            println!("{:?}", h);
            match h.get(&"Content-Length"){
                Some(&length) => {
                    let mut length_number = length.parse::<usize>().unwrap();
                    println!("{:?} :: {:?}", length_number, i.len());
                    match h.get(&"WARC-Truncated"){
                        Some(_) =>{
                            length_number = std::cmp::min(length_number, i.len());
                        }
                        _ => {}
                    }
                    println!("{:?} :: {:?}", length_number, i.len());
                    let content = &i[0..length_number as usize];
                    let content_str = str::from_utf8(content).unwrap();
                    i = &i[length_number as usize ..];
                    h.insert(&"CONTENT", content_str);
                    IResult::Done(i, h)
                }
                None => {
                    IResult::Incomplete(Needed::Size(1))
                }
            }

        },
        IResult::Incomplete(a)     => IResult::Incomplete(a),
        IResult::Error(a)          => IResult::Error(a)
    }
}

named!(pub records<&[u8], Vec<HashMap<&str,&str>> >, many1!(record));
<commit_msg>Move to [u8]s<commit_after>#[macro_use]
extern crate nom;
use nom::{IResult, space, multispace, Needed, Err};
use nom::IResult::*;
use std::str;
use std::collections::HashMap;

fn version_number(input: &[u8]) -> IResult<&[u8], &[u8]> {
    for (idx, chr) in input.iter().enumerate() {
        match *chr {
            46 | 48...57  => continue,
            _ => return IResult::Done(&input[idx..], &input[..idx]),
        }
    }
    IResult::Incomplete(Needed::Size(1))
}

fn just_about_everything(input: &[u8]) -> IResult<&[u8], &[u8]> {
    for (idx, chr) in input.iter().enumerate() {
        match *chr {
            32...126 => continue,
            _ => return IResult::Done(&input[idx..], &input[..idx]),
        }
    }
    IResult::Incomplete(Needed::Size(1))
}
fn token(input: &[u8]) -> IResult<&[u8], &[u8]> {
    for (idx, chr) in input.iter().enumerate() {
        match *chr {
            33 | 35...39 | 42 | 43 | 45 | 48...57 | 65...90 | 94...122 | 124 => continue,
            _ => return IResult::Done(&input[idx..], &input[..idx]),
        }
    }
    IResult::Incomplete(Needed::Size(1))
}
named!(init_line <&[u8], (&str, &str)>,
    chain!(
        multispace?                  ~
        tag!("WARC")                ~
        tag!("/")                   ~
        space?                      ~
        version: map_res!(version_number, str::from_utf8)~
        tag!("\r")?                 ~
        tag!("\n")                  ,
        || {("WARCVERSION", version)}
        )
    );
named!(header_match <&[u8], (&str, &str)>,
    chain!(
        name: map_res!(token, str::from_utf8)~
        space?                      ~
        tag!(":")                   ~
        space?                      ~
        value: map_res!(just_about_everything, str::from_utf8)~
        tag!("\r")?                 ~
        tag!("\n")                  ,
        || {(name, value)}
        )
    );

named!(header_aggregator<&[u8], Vec<(&str,&str)> >, many1!(header_match));

named!(warc_header<&[u8], ((&str, &str), Vec<(&str,&str)>) >,
chain!(
    version: init_line              ~
    headers: header_aggregator      ,
    move ||{(version, headers)}
    )
);
pub struct Record{
    headers: HashMap<String, String>,
    content: Vec<u8>
}
pub fn record(input: &[u8]) -> IResult<&[u8], Record>{
    let mut h: HashMap<String,  String> = HashMap::new();
    match warc_header(input) {
        IResult::Done(mut i, tuple_vec) => {
            let (name, version) = tuple_vec.0;
            h.insert(name.to_string(), version.to_string());
            let headers =  tuple_vec.1;
            for &(k,ref v) in headers.iter() {
                h.insert(k.to_string(), v.clone().to_string());
            }
            let mut content: &[u8];
            match h.get("Content-Length"){
                Some(length) => {
                    let mut length_number = length.parse::<usize>().unwrap();
                    println!("{:?} :: {:?}", length_number, i.len());
                    match h.get("WARC-Truncated"){
                        Some(_) =>{
                            length_number = std::cmp::min(length_number, i.len());
                        }
                        _ => {}
                    }
                    println!("{:?} :: {:?}", length_number, i.len());
                    content = &i[0..length_number as usize];
                    i = &i[length_number as usize ..];
                    let record = Record{headers: h, content: content.to_vec()};
                    IResult::Done(i, record)
                }
                None => {
                    IResult::Incomplete(Needed::Size(1))
                }
            }

        },
        IResult::Incomplete(a)     => IResult::Incomplete(a),
        IResult::Error(a)          => IResult::Error(a)
    }
}

named!(pub records<&[u8], Vec<Record> >, many1!(record));
<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)]

#[macro_use]
extern crate tracing;

use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fmt;

use conduit::{box_error, Handler, HandlerResult, Method, RequestExt};
use route_recognizer::{Match, Params, Router};

static UNKNOWN_METHOD: &str = "Invalid method";
static NOT_FOUND: &str = "Path not found";

#[derive(Default)]
pub struct RouteBuilder {
    routers: HashMap<Method, Router<WrappedHandler>>,
}

#[derive(Clone, Copy)]
pub struct RoutePattern(&'static str);

impl RoutePattern {
    pub fn pattern(&self) -> &str {
        self.0
    }
}

pub struct WrappedHandler {
    pattern: RoutePattern,
    handler: Box<dyn Handler>,
}

impl conduit::Handler for WrappedHandler {
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        self.handler.call(request)
    }
}

#[derive(Debug)]
pub enum RouterError {
    UnknownMethod,
    PathNotFound,
}

impl RouteBuilder {
    pub fn new() -> Self {
        Self {
            routers: HashMap::new(),
        }
    }

    #[instrument(level = "trace", skip(self))]
    pub fn recognize<'a>(
        &'a self,
        method: &Method,
        path: &str,
    ) -> Result<Match<&WrappedHandler>, RouterError> {
        match self.routers.get(method) {
            Some(router) => router.recognize(path).or(Err(RouterError::PathNotFound)),
            None => Err(RouterError::UnknownMethod),
        }
    }

    #[instrument(level = "trace", skip(self, handler))]
    pub fn map<H: Handler>(
        &mut self,
        method: Method,
        pattern: &'static str,
        handler: H,
    ) -> &mut Self {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            let wrapped_handler = WrappedHandler {
                pattern: RoutePattern(pattern),
                handler: Box::new(handler),
            };
            router.add(pattern, wrapped_handler);
        }
        self
    }

    pub fn get<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::GET, pattern, handler)
    }

    pub fn post<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::POST, pattern, handler)
    }

    pub fn put<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::PUT, pattern, handler)
    }

    pub fn delete<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::DELETE, pattern, handler)
    }

    pub fn head<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::HEAD, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    #[instrument(level = "trace", skip(self, request))]
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        let mut m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => {
                    info!("{}", e);
                    return Err(box_error(e));
                }
            }
        };

        // We don't have `pub` access to the fields to destructure `Params`, so swap with an empty
        // value to avoid an allocation.
        let mut params = Params::new();
        std::mem::swap(m.params_mut(), &mut params);

        let pattern = m.handler().pattern;
        debug!(pattern = pattern.0, "matching route handler found");

        {
            let extensions = request.mut_extensions();
            extensions.insert(pattern);
            extensions.insert(params);
        }

        let span = trace_span!("handler", pattern = pattern.0);
        span.in_scope(|| m.handler().call(request))
    }
}

impl Error for RouterError {
    fn description(&self) -> &str {
        match self {
            Self::UnknownMethod => UNKNOWN_METHOD,
            Self::PathNotFound => NOT_FOUND,
        }
    }
}

impl fmt::Display for RouterError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        #[allow(deprecated)]
        self.description().fmt(f)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a Params;
}

impl<'a> RequestParams<'a> for &'a (dyn RequestExt + 'a) {
    fn params(self) -> &'a Params {
        self.extensions().find::<Params>().expect("Missing params")
    }
}

#[cfg(test)]
mod tests {
    use super::{RequestParams, RouteBuilder, RoutePattern};

    use conduit::{Body, Handler, Method, Response, StatusCode};
    use conduit_test::{MockRequest, ResponseExt};

    lazy_static::lazy_static! {
        static ref TRACING: () = {
            tracing_subscriber::FmtSubscriber::builder()
                .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
                .with_span_events(tracing_subscriber::fmt::format::FmtSpan::FULL)
                .with_test_writer()
                .init();
        };
    }

    #[test]
    fn basic_get() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::GET, "/posts/1");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"1, GET, /posts/:id"[..]);
    }

    #[test]
    fn basic_post() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::POST, "/posts/10");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"10, POST, /posts/:id"[..]);
    }

    #[test]
    fn path_not_found() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::POST, "/nonexistent");
        let err = router.call(&mut req).err().unwrap();

        assert_eq!(err.to_string(), super::NOT_FOUND);
    }

    #[test]
    fn unknown_method() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::DELETE, "/posts/1");
        let err = router.call(&mut req).err().unwrap();

        assert_eq!(err.to_string(), super::UNKNOWN_METHOD);
    }

    #[test]
    fn catch_all() {
        lazy_static::initialize(&TRACING);

        let mut router = RouteBuilder::new();
        router.get("/*", test_handler);

        let mut req = MockRequest::new(Method::GET, "/foo");
        let res = router.call(&mut req).expect("No response");
        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b", GET, /*"[..]);
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut dyn conduit::RequestExt) -> conduit::HttpResult {
        let res = vec![
            req.params().find("id").unwrap_or("").to_string(),
            format!("{:?}", req.method()),
            req.extensions()
                .find::<RoutePattern>()
                .unwrap()
                .pattern()
                .to_string(),
        ];

        let bytes = res.join(", ").into_bytes();
        Response::builder().body(Body::from_vec(bytes))
    }
}
<commit_msg>Drop `pub` from a struct and method<commit_after>#![warn(rust_2018_idioms)]

#[macro_use]
extern crate tracing;

use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fmt;

use conduit::{box_error, Handler, HandlerResult, Method, RequestExt};
use route_recognizer::{Match, Params, Router};

static UNKNOWN_METHOD: &str = "Invalid method";
static NOT_FOUND: &str = "Path not found";

#[derive(Default)]
pub struct RouteBuilder {
    routers: HashMap<Method, Router<WrappedHandler>>,
}

#[derive(Clone, Copy)]
pub struct RoutePattern(&'static str);

impl RoutePattern {
    pub fn pattern(&self) -> &str {
        self.0
    }
}

struct WrappedHandler {
    pattern: RoutePattern,
    handler: Box<dyn Handler>,
}

impl conduit::Handler for WrappedHandler {
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        self.handler.call(request)
    }
}

#[derive(Debug)]
pub enum RouterError {
    UnknownMethod,
    PathNotFound,
}

impl RouteBuilder {
    pub fn new() -> Self {
        Self {
            routers: HashMap::new(),
        }
    }

    #[instrument(level = "trace", skip(self))]
    fn recognize<'a>(
        &'a self,
        method: &Method,
        path: &str,
    ) -> Result<Match<&WrappedHandler>, RouterError> {
        match self.routers.get(method) {
            Some(router) => router.recognize(path).or(Err(RouterError::PathNotFound)),
            None => Err(RouterError::UnknownMethod),
        }
    }

    #[instrument(level = "trace", skip(self, handler))]
    pub fn map<H: Handler>(
        &mut self,
        method: Method,
        pattern: &'static str,
        handler: H,
    ) -> &mut Self {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            let wrapped_handler = WrappedHandler {
                pattern: RoutePattern(pattern),
                handler: Box::new(handler),
            };
            router.add(pattern, wrapped_handler);
        }
        self
    }

    pub fn get<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::GET, pattern, handler)
    }

    pub fn post<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::POST, pattern, handler)
    }

    pub fn put<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::PUT, pattern, handler)
    }

    pub fn delete<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::DELETE, pattern, handler)
    }

    pub fn head<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut Self {
        self.map(Method::HEAD, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    #[instrument(level = "trace", skip(self, request))]
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        let mut m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => {
                    info!("{}", e);
                    return Err(box_error(e));
                }
            }
        };

        // We don't have `pub` access to the fields to destructure `Params`, so swap with an empty
        // value to avoid an allocation.
        let mut params = Params::new();
        std::mem::swap(m.params_mut(), &mut params);

        let pattern = m.handler().pattern;
        debug!(pattern = pattern.0, "matching route handler found");

        {
            let extensions = request.mut_extensions();
            extensions.insert(pattern);
            extensions.insert(params);
        }

        let span = trace_span!("handler", pattern = pattern.0);
        span.in_scope(|| m.handler().call(request))
    }
}

impl Error for RouterError {
    fn description(&self) -> &str {
        match self {
            Self::UnknownMethod => UNKNOWN_METHOD,
            Self::PathNotFound => NOT_FOUND,
        }
    }
}

impl fmt::Display for RouterError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        #[allow(deprecated)]
        self.description().fmt(f)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a Params;
}

impl<'a> RequestParams<'a> for &'a (dyn RequestExt + 'a) {
    fn params(self) -> &'a Params {
        self.extensions().find::<Params>().expect("Missing params")
    }
}

#[cfg(test)]
mod tests {
    use super::{RequestParams, RouteBuilder, RoutePattern};

    use conduit::{Body, Handler, Method, Response, StatusCode};
    use conduit_test::{MockRequest, ResponseExt};

    lazy_static::lazy_static! {
        static ref TRACING: () = {
            tracing_subscriber::FmtSubscriber::builder()
                .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
                .with_span_events(tracing_subscriber::fmt::format::FmtSpan::FULL)
                .with_test_writer()
                .init();
        };
    }

    #[test]
    fn basic_get() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::GET, "/posts/1");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"1, GET, /posts/:id"[..]);
    }

    #[test]
    fn basic_post() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::POST, "/posts/10");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"10, POST, /posts/:id"[..]);
    }

    #[test]
    fn path_not_found() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::POST, "/nonexistent");
        let err = router.call(&mut req).err().unwrap();

        assert_eq!(err.to_string(), super::NOT_FOUND);
    }

    #[test]
    fn unknown_method() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::DELETE, "/posts/1");
        let err = router.call(&mut req).err().unwrap();

        assert_eq!(err.to_string(), super::UNKNOWN_METHOD);
    }

    #[test]
    fn catch_all() {
        lazy_static::initialize(&TRACING);

        let mut router = RouteBuilder::new();
        router.get("/*", test_handler);

        let mut req = MockRequest::new(Method::GET, "/foo");
        let res = router.call(&mut req).expect("No response");
        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b", GET, /*"[..]);
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut dyn conduit::RequestExt) -> conduit::HttpResult {
        let res = vec![
            req.params().find("id").unwrap_or("").to_string(),
            format!("{:?}", req.method()),
            req.extensions()
                .find::<RoutePattern>()
                .unwrap()
                .pattern()
                .to_string(),
        ];

        let bytes = res.join(", ").into_bytes();
        Response::builder().body(Body::from_vec(bytes))
    }
}
<|endoftext|>


<commit_before>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a microkernel that supports `x86_64` systems and
//! provides Unix-like syscalls for primarily Rust applications

// Useful for adding comments about different branches
#![allow(clippy::if_same_then_else)]
// Useful in the syscall function
#![allow(clippy::many_single_char_names)]
// Used for context::context
#![allow(clippy::module_inception)]
// Not implementing default is sometimes useful in the case something has significant cost
// to allocate. If you implement default, it can be allocated without evidence using the
// ..Default::default() syntax. Not fun in kernel space
#![allow(clippy::new_without_default)]
// Used to make it nicer to return errors, for example, .ok_or(Error::new(ESRCH))
#![allow(clippy::or_fun_call)]
// This is needed in some cases, like for syscall
#![allow(clippy::too_many_arguments)]
// There is no harm in this being done
#![allow(clippy::useless_format)]

// TODO: address ocurrances and then deny
#![warn(clippy::not_unsafe_ptr_arg_deref)]
// TODO: address ocurrances and then deny
#![warn(clippy::cast_ptr_alignment)]
// Indexing a slice can cause panics and that is something we always want to avoid
// in kernel code. Use .get and return an error instead
// TODO: address ocurrances and then deny
#![warn(clippy::indexing_slicing)]
// Overflows are very, very bad in kernel code as it may provide an attack vector for
// userspace applications, and it is only checked in debug builds
// TODO: address ocurrances and then deny
#![warn(clippy::integer_arithmetic)]
// Avoid panicking in the kernel without information about the panic. Use expect
// TODO: address ocurrances and then deny
#![warn(clippy::result_unwrap_used)]

// This is usually a serious issue - a missing import of a define where it is interpreted
// as a catch-all variable in a match, for example
#![deny(unreachable_patterns)]

#![feature(allocator_api)]
#![feature(asm)] // TODO: Relax requirements of most asm invocations
#![feature(concat_idents)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(global_asm)]
#![feature(integer_atomics)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(ptr_internals)]
#![feature(thread_local)]
#![no_std]

pub extern crate x86;

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate linked_list_allocator;
extern crate rustc_demangle;
extern crate spin;
#[cfg(feature = "slab")]
extern crate slab_allocator;

use alloc::vec::Vec;
use core::sync::atomic::{AtomicUsize, Ordering};

use crate::scheme::{FileHandle, SchemeNamespace};

pub use crate::consts::*;

#[macro_use]
/// Shared data structures
pub mod common;

/// Architecture-dependent stuff
#[macro_use]
pub mod arch;
pub use crate::arch::*;

/// Constants like memory locations
pub mod consts;

/// Heap allocators
pub mod allocator;

/// ACPI table parsing
#[cfg(feature = "acpi")]
mod acpi;

/// Context management
pub mod context;

/// Architecture-independent devices
pub mod devices;

/// ELF file parsing
#[cfg(not(feature="doc"))]
pub mod elf;

/// Event handling
pub mod event;

/// External functions
pub mod externs;

/// Logging
pub mod log;

/// Memory management
pub mod memory;

/// Panic
#[cfg(not(any(feature="doc", test)))]
pub mod panic;

/// Process tracing
pub mod ptrace;

/// Schemes, filesystem handlers
pub mod scheme;

/// Synchronization primitives
pub mod sync;

/// Syscall handlers
pub mod syscall;

/// Time
pub mod time;

/// Tests
#[cfg(test)]
pub mod tests;

#[global_allocator]
static ALLOCATOR: allocator::Allocator = allocator::Allocator;

/// A unique number that identifies the current CPU - used for scheduling
#[thread_local]
static CPU_ID: AtomicUsize = AtomicUsize::new(0);

/// Get the current CPU's scheduling ID
#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

/// The count of all CPUs that can have work scheduled
static CPU_COUNT : AtomicUsize = AtomicUsize::new(0);

/// Get the number of CPUs currently active
#[inline(always)]
pub fn cpu_count() -> usize {
    CPU_COUNT.load(Ordering::Relaxed)
}

static mut INIT_ENV: &[u8] = &[];

/// Initialize userspace by running the initfs:bin/init process
/// This function will also set the CWD to initfs:bin and open debug: as stdio
pub extern fn userspace_init() {
    let path = b"initfs:/bin/init";
    let env = unsafe { INIT_ENV };

    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));

    assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2));

    let fd = syscall::open(path, syscall::flag::O_RDONLY).expect("failed to open init");

    let mut args = Vec::new();
    args.push(path.to_vec().into_boxed_slice());

    let mut vars = Vec::new();
    for var in env.split(|b| *b == b'\n') {
        if ! var.is_empty() {
            vars.push(var.to_vec().into_boxed_slice());
        }
    }

    syscall::fexec_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice(), None, None).expect("failed to execute init");

    panic!("init returned");
}

/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
pub fn kmain(cpus: usize, env: &'static [u8]) -> ! {
    CPU_ID.store(0, Ordering::SeqCst);
    CPU_COUNT.store(cpus, Ordering::SeqCst);
    unsafe { INIT_ENV = env };

    //Initialize the first context, stored in kernel/src/context/mod.rs
    context::init();

    let pid = syscall::getpid();
    println!("BSP: {:?} {}", pid, cpus);
    println!("Env: {:?}", ::core::str::from_utf8(env));

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.rns = SchemeNamespace::from(1);
            context.ens = SchemeNamespace::from(1);
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
}

/// This is the main kernel entry point for secondary CPUs
#[allow(unreachable_code, unused_variables)]
pub fn kmain_ap(id: usize) -> ! {
    CPU_ID.store(id, Ordering::SeqCst);

    if cfg!(feature = "multi_core") {
        context::init();

        let pid = syscall::getpid();
        println!("AP {}: {:?}", id, pid);

        loop {
            unsafe {
                interrupt::disable();
                if context::switch() {
                    interrupt::enable_and_nop();
                } else {
                    // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                    interrupt::enable_and_halt();
                }
            }
        }
    } else {
        println!("AP {}: Disabled", id);

        loop {
            unsafe {
                interrupt::disable();
                interrupt::halt();
            }
        }
    }
}

/// Allow exception handlers to send signal to arch-independant kernel
#[no_mangle]
pub extern fn ksignal(signal: usize) {
    println!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id());
    {
        let contexts = context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            println!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
        }
    }

    // Try running kill(getpid(), signal), but fallback to exiting
    syscall::getpid()
        .and_then(|pid| syscall::kill(pid, signal).map(|_| ()))
        .unwrap_or_else(|_| {
            syscall::exit(signal & 0x7F);
        });
}
<commit_msg>use logging instead of println<commit_after>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a microkernel that supports `x86_64` systems and
//! provides Unix-like syscalls for primarily Rust applications

// Useful for adding comments about different branches
#![allow(clippy::if_same_then_else)]
// Useful in the syscall function
#![allow(clippy::many_single_char_names)]
// Used for context::context
#![allow(clippy::module_inception)]
// Not implementing default is sometimes useful in the case something has significant cost
// to allocate. If you implement default, it can be allocated without evidence using the
// ..Default::default() syntax. Not fun in kernel space
#![allow(clippy::new_without_default)]
// Used to make it nicer to return errors, for example, .ok_or(Error::new(ESRCH))
#![allow(clippy::or_fun_call)]
// This is needed in some cases, like for syscall
#![allow(clippy::too_many_arguments)]
// There is no harm in this being done
#![allow(clippy::useless_format)]

// TODO: address ocurrances and then deny
#![warn(clippy::not_unsafe_ptr_arg_deref)]
// TODO: address ocurrances and then deny
#![warn(clippy::cast_ptr_alignment)]
// Indexing a slice can cause panics and that is something we always want to avoid
// in kernel code. Use .get and return an error instead
// TODO: address ocurrances and then deny
#![warn(clippy::indexing_slicing)]
// Overflows are very, very bad in kernel code as it may provide an attack vector for
// userspace applications, and it is only checked in debug builds
// TODO: address ocurrances and then deny
#![warn(clippy::integer_arithmetic)]
// Avoid panicking in the kernel without information about the panic. Use expect
// TODO: address ocurrances and then deny
#![warn(clippy::result_unwrap_used)]

// This is usually a serious issue - a missing import of a define where it is interpreted
// as a catch-all variable in a match, for example
#![deny(unreachable_patterns)]

#![feature(allocator_api)]
#![feature(asm)] // TODO: Relax requirements of most asm invocations
#![feature(concat_idents)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(global_asm)]
#![feature(integer_atomics)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(ptr_internals)]
#![feature(thread_local)]
#![no_std]

pub extern crate x86;

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate linked_list_allocator;
extern crate rustc_demangle;
extern crate spin;
#[cfg(feature = "slab")]
extern crate slab_allocator;

use alloc::vec::Vec;
use core::sync::atomic::{AtomicUsize, Ordering};

use crate::scheme::{FileHandle, SchemeNamespace};

pub use crate::consts::*;

#[macro_use]
/// Shared data structures
pub mod common;

/// Architecture-dependent stuff
#[macro_use]
pub mod arch;
pub use crate::arch::*;

use crate::log::info;

/// Constants like memory locations
pub mod consts;

/// Heap allocators
pub mod allocator;

/// ACPI table parsing
#[cfg(feature = "acpi")]
mod acpi;

/// Context management
pub mod context;

/// Architecture-independent devices
pub mod devices;

/// ELF file parsing
#[cfg(not(feature="doc"))]
pub mod elf;

/// Event handling
pub mod event;

/// External functions
pub mod externs;

/// Logging
pub mod log;

/// Memory management
pub mod memory;

/// Panic
#[cfg(not(any(feature="doc", test)))]
pub mod panic;

/// Process tracing
pub mod ptrace;

/// Schemes, filesystem handlers
pub mod scheme;

/// Synchronization primitives
pub mod sync;

/// Syscall handlers
pub mod syscall;

/// Time
pub mod time;

/// Tests
#[cfg(test)]
pub mod tests;

#[global_allocator]
static ALLOCATOR: allocator::Allocator = allocator::Allocator;

/// A unique number that identifies the current CPU - used for scheduling
#[thread_local]
static CPU_ID: AtomicUsize = AtomicUsize::new(0);

/// Get the current CPU's scheduling ID
#[inline(always)]
pub fn cpu_id() -> usize {
    CPU_ID.load(Ordering::Relaxed)
}

/// The count of all CPUs that can have work scheduled
static CPU_COUNT : AtomicUsize = AtomicUsize::new(0);

/// Get the number of CPUs currently active
#[inline(always)]
pub fn cpu_count() -> usize {
    CPU_COUNT.load(Ordering::Relaxed)
}

static mut INIT_ENV: &[u8] = &[];

/// Initialize userspace by running the initfs:bin/init process
/// This function will also set the CWD to initfs:bin and open debug: as stdio
pub extern fn userspace_init() {
    let path = b"initfs:/bin/init";
    let env = unsafe { INIT_ENV };

    assert_eq!(syscall::chdir(b"initfs:"), Ok(0));

    assert_eq!(syscall::open(b"debug:", syscall::flag::O_RDONLY).map(FileHandle::into), Ok(0));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(1));
    assert_eq!(syscall::open(b"debug:", syscall::flag::O_WRONLY).map(FileHandle::into), Ok(2));

    let fd = syscall::open(path, syscall::flag::O_RDONLY).expect("failed to open init");

    let mut args = Vec::new();
    args.push(path.to_vec().into_boxed_slice());

    let mut vars = Vec::new();
    for var in env.split(|b| *b == b'\n') {
        if ! var.is_empty() {
            vars.push(var.to_vec().into_boxed_slice());
        }
    }

    syscall::fexec_kernel(fd, args.into_boxed_slice(), vars.into_boxed_slice(), None, None).expect("failed to execute init");

    panic!("init returned");
}

/// This is the kernel entry point for the primary CPU. The arch crate is responsible for calling this
pub fn kmain(cpus: usize, env: &'static [u8]) -> ! {
    CPU_ID.store(0, Ordering::SeqCst);
    CPU_COUNT.store(cpus, Ordering::SeqCst);
    unsafe { INIT_ENV = env };

    //Initialize the first context, stored in kernel/src/context/mod.rs
    context::init();

    let pid = syscall::getpid();
    info!("BSP: {:?} {}", pid, cpus);
    info!("Env: {:?}", ::core::str::from_utf8(env));

    match context::contexts_mut().spawn(userspace_init) {
        Ok(context_lock) => {
            let mut context = context_lock.write();
            context.rns = SchemeNamespace::from(1);
            context.ens = SchemeNamespace::from(1);
            context.status = context::Status::Runnable;
        },
        Err(err) => {
            panic!("failed to spawn userspace_init: {:?}", err);
        }
    }

    loop {
        unsafe {
            interrupt::disable();
            if context::switch() {
                interrupt::enable_and_nop();
            } else {
                // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                interrupt::enable_and_halt();
            }
        }
    }
}

/// This is the main kernel entry point for secondary CPUs
#[allow(unreachable_code, unused_variables)]
pub fn kmain_ap(id: usize) -> ! {
    CPU_ID.store(id, Ordering::SeqCst);

    if cfg!(feature = "multi_core") {
        context::init();

        let pid = syscall::getpid();
        info!("AP {}: {:?}", id, pid);

        loop {
            unsafe {
                interrupt::disable();
                if context::switch() {
                    interrupt::enable_and_nop();
                } else {
                    // Enable interrupts, then halt CPU (to save power) until the next interrupt is actually fired.
                    interrupt::enable_and_halt();
                }
            }
        }
    } else {
        info!("AP {}: Disabled", id);

        loop {
            unsafe {
                interrupt::disable();
                interrupt::halt();
            }
        }
    }
}

/// Allow exception handlers to send signal to arch-independant kernel
#[no_mangle]
pub extern fn ksignal(signal: usize) {
    info!("SIGNAL {}, CPU {}, PID {:?}", signal, cpu_id(), context::context_id());
    {
        let contexts = context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            info!("NAME {}", unsafe { ::core::str::from_utf8_unchecked(&context.name.lock()) });
        }
    }

    // Try running kill(getpid(), signal), but fallback to exiting
    syscall::getpid()
        .and_then(|pid| syscall::kill(pid, signal).map(|_| ()))
        .unwrap_or_else(|_| {
            syscall::exit(signal & 0x7F);
        });
}
<|endoftext|>


<commit_before>#![deny(missing_debug_implementations)]

#[macro_use]
extern crate bitflags;
extern crate jansson_sys;
extern crate janus_plugin_sys as ffi;
extern crate glib_sys as glib;
extern crate libc;
extern crate serde;

pub use debug::LogLevel;
pub use debug::log;
pub use jansson::{JanssonDecodingFlags, JanssonEncodingFlags, JanssonValue, RawJanssonValue};
pub use session::SessionWrapper;
pub use ffi::events::janus_eventhandler as EventHandler;
pub use ffi::plugin::janus_callbacks as PluginCallbacks;
pub use ffi::plugin::janus_plugin as Plugin;
pub use ffi::plugin::janus_plugin_result as RawPluginResult;
pub use ffi::plugin::janus_plugin_session as PluginSession;
use ffi::plugin::janus_plugin_result_type as PluginResultType;
use std::error::Error;
use std::fmt;
use std::ffi::CStr;
use std::mem;
use std::ops::Deref;
use std::os::raw::{c_char, c_int};
use std::ptr;

pub mod debug;
pub mod rtcp;
pub mod sdp;
pub mod session;
pub mod jansson;
pub mod utils;

#[cfg(feature="refcount")]
pub mod refcount;

bitflags! {
    /// Flags that control which events an event handler receives.
    pub struct JanusEventType: u32 {
        const JANUS_EVENT_TYPE_SESSION   = 1 << 0;
        const JANUS_EVENT_TYPE_HANDLE    = 1 << 1;
        const JANUS_EVENT_TYPE_JSEP      = 1 << 3; // yes, really
        const JANUS_EVENT_TYPE_WEBRTC    = 1 << 4;
        const JANUS_EVENT_TYPE_MEDIA     = 1 << 5;
        const JANUS_EVENT_TYPE_PLUGIN    = 1 << 6;
        const JANUS_EVENT_TYPE_TRANSPORT = 1 << 7;
        const JANUS_EVENT_TYPE_CORE      = 1 << 8;
    }
}

/// An error emitted by the Janus core in response to a plugin.
#[derive(Debug, Clone, Copy)]
pub struct JanusError(pub i32);

impl JanusError {
    /// Returns Janus's description text for this error.
    pub fn to_cstr(&self) -> &'static CStr {
        unsafe { CStr::from_ptr(ffi::janus_get_api_error(self.0)) }
    }
}

impl Error for JanusError {
    fn description(&self) -> &'static str {
        self.to_cstr().to_str().unwrap()
    }
}

impl fmt::Display for JanusError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} (code: {})", self.description(), self.0)
    }
}

/// Converts a Janus gateway result code to either success or a potential error.
pub fn get_result(error: i32) -> Result<(), JanusError> {
    match error {
        0 => Ok(()),
        e => Err(JanusError(e))
    }
}

/// A Janus plugin result; what a plugin returns to the gateway as a direct response to a signalling message.
#[derive(Debug)]
pub struct PluginResult {
    ptr: *mut RawPluginResult,
}

impl PluginResult {
    /// Creates a new plugin result.
    pub unsafe fn new(type_: PluginResultType, text: *const c_char, content: *mut RawJanssonValue) -> Self {
        Self { ptr: ffi::plugin::janus_plugin_result_new(type_, text, content) }
    }

    /// Creates a plugin result indicating a synchronously successful request. The provided response
    /// JSON will be passed back to the client.
    pub fn ok(response: JanssonValue) -> Self {
        unsafe { Self::new(PluginResultType::JANUS_PLUGIN_OK, ptr::null(), response.into_raw()) }
    }

    /// Creates a plugin result indicating an asynchronous request in progress. If provided, the hint text
    /// will be synchronously passed back to the client in the acknowledgement.
    pub fn ok_wait(hint: Option<&'static CStr>) -> Self {
        let hint_ptr = hint.map(|x| x.as_ptr()).unwrap_or_else(ptr::null);
        unsafe { Self::new(PluginResultType::JANUS_PLUGIN_OK_WAIT, hint_ptr, ptr::null_mut()) }
    }

    /// Creates a plugin result indicating an error. The provided error text will be synchronously passed
    /// back to the client.
    pub fn error(msg: &'static CStr) -> Self {
        unsafe { Self::new(PluginResultType::JANUS_PLUGIN_ERROR, msg.as_ptr(), ptr::null_mut()) }
    }

    /// Transfers ownership of this result to the wrapped raw pointer. The consumer is responsible for calling
    /// `janus_plugin_result_destroy` on the pointer when finished.
    pub fn into_raw(self) -> *mut RawPluginResult {
        let ptr = self.ptr;
        mem::forget(self);
        ptr
    }
}

impl Deref for PluginResult {
    type Target = RawPluginResult;

    fn deref(&self) -> &RawPluginResult {
        unsafe { &*self.ptr }
    }
}

impl Drop for PluginResult {
    fn drop(&mut self) {
        unsafe { ffi::plugin::janus_plugin_result_destroy(self.ptr) }
    }
}

unsafe impl Send for PluginResult {}

#[derive(Debug)]
/// Represents metadata about this library which Janus can query at runtime.
pub struct LibraryMetadata<'a> {
    pub api_version: c_int,
    pub version: c_int,
    pub version_str: &'a CStr,
    pub description: &'a CStr,
    pub name: &'a CStr,
    pub author: &'a CStr,
    pub package: &'a CStr,
}

/// Helper macro to produce a Janus plugin instance. Should be called with
/// a `LibraryMetadata` instance and a series of exported plugin callbacks.
#[macro_export]
macro_rules! build_plugin {
    ($md:expr, $($cb:ident),*) => {{
        extern "C" fn get_api_compatibility() -> c_int { $md.api_version }
        extern "C" fn get_version() -> c_int { $md.version }
        extern "C" fn get_version_string() -> *const c_char { $md.version_str.as_ptr() }
        extern "C" fn get_description() -> *const c_char { $md.description.as_ptr() }
        extern "C" fn get_name() -> *const c_char { $md.name.as_ptr() }
        extern "C" fn get_author() -> *const c_char { $md.author.as_ptr() }
        extern "C" fn get_package() -> *const c_char { $md.package.as_ptr() }
        $crate::Plugin {
            get_api_compatibility,
            get_version,
            get_version_string,
            get_description,
            get_name,
            get_author,
            get_package,
            $($cb,)*
        }
    }}
}

/// Macro to export a Janus plugin instance from this module.
#[macro_export]
macro_rules! export_plugin {
    ($pl:expr) => {
        /// Called by Janus to create an instance of this plugin, using the provided callbacks to dispatch events.
        #[no_mangle]
        pub extern "C" fn create() -> *const $crate::Plugin { $pl }
    }
}

/// Helper macro to produce a Janus event handler instance. Should be called with
/// a `LibraryMetadata` instance and a series of exported event handler callbacks.
#[macro_export]
macro_rules! build_eventhandler {
    ($md:expr, $mask:expr, $($cb:ident),*) => {{
        extern "C" fn get_api_compatibility() -> c_int { $md.api_version }
        extern "C" fn get_version() -> c_int { $md.version }
        extern "C" fn get_version_string() -> *const c_char { $md.version_str.as_ptr() }
        extern "C" fn get_description() -> *const c_char { $md.description.as_ptr() }
        extern "C" fn get_name() -> *const c_char { $md.name.as_ptr() }
        extern "C" fn get_author() -> *const c_char { $md.author.as_ptr() }
        extern "C" fn get_package() -> *const c_char { $md.package.as_ptr() }
        $crate::EventHandler {
            events_mask: $mask,
            get_api_compatibility,
            get_version,
            get_version_string,
            get_description,
            get_name,
            get_author,
            get_package,
            $($cb,)*
        }
    }}
}

/// Macro to export a Janus event handler instance from this module.
#[macro_export]
macro_rules! export_eventhandler {
    ($evh:expr) => {
        /// Called by Janus to create an instance of this event handler, using the provided callbacks to dispatch events.
        #[no_mangle]
        pub extern "C" fn create() -> *const $crate::EventHandler { $evh }
    }
}
<commit_msg>Tweak Janus error interface, add JanusResult<commit_after>#![deny(missing_debug_implementations)]

#[macro_use]
extern crate bitflags;
extern crate jansson_sys;
extern crate janus_plugin_sys as ffi;
extern crate glib_sys as glib;
extern crate libc;
extern crate serde;

pub use debug::LogLevel;
pub use debug::log;
pub use jansson::{JanssonDecodingFlags, JanssonEncodingFlags, JanssonValue, RawJanssonValue};
pub use session::SessionWrapper;
pub use ffi::events::janus_eventhandler as EventHandler;
pub use ffi::plugin::janus_callbacks as PluginCallbacks;
pub use ffi::plugin::janus_plugin as Plugin;
pub use ffi::plugin::janus_plugin_result as RawPluginResult;
pub use ffi::plugin::janus_plugin_session as PluginSession;
use ffi::plugin::janus_plugin_result_type as PluginResultType;
use std::error::Error;
use std::fmt;
use std::ffi::CStr;
use std::mem;
use std::ops::Deref;
use std::os::raw::{c_char, c_int};
use std::ptr;

pub mod debug;
pub mod rtcp;
pub mod sdp;
pub mod session;
pub mod jansson;
pub mod utils;

#[cfg(feature="refcount")]
pub mod refcount;

bitflags! {
    /// Flags that control which events an event handler receives.
    pub struct JanusEventType: u32 {
        const JANUS_EVENT_TYPE_SESSION   = 1 << 0;
        const JANUS_EVENT_TYPE_HANDLE    = 1 << 1;
        const JANUS_EVENT_TYPE_JSEP      = 1 << 3; // yes, really
        const JANUS_EVENT_TYPE_WEBRTC    = 1 << 4;
        const JANUS_EVENT_TYPE_MEDIA     = 1 << 5;
        const JANUS_EVENT_TYPE_PLUGIN    = 1 << 6;
        const JANUS_EVENT_TYPE_TRANSPORT = 1 << 7;
        const JANUS_EVENT_TYPE_CORE      = 1 << 8;
    }
}

/// An error emitted by the Janus core in response to a plugin pushing an event.
#[derive(Debug, Clone, Copy)]
pub struct JanusError(i32);

/// A result from pushing an event to Janus core.
type JanusResult = Result<(), JanusError>;

impl JanusError {
    /// The numeric Janus error code for this error. (See apierror.h.)
    pub fn code(&self) -> i32 {
        self.0
    }
    /// Returns Janus's description text for this error.
    pub fn to_cstr(&self) -> &'static CStr {
        unsafe { CStr::from_ptr(ffi::janus_get_api_error(self.code())) }
    }
    /// Converts a Janus result code to either success or a potential error.
    pub fn from(val: i32) -> JanusResult {
        match val {
            0 => Ok(()),
            e => Err(JanusError(e))
        }
    }
}

impl Error for JanusError {
    fn description(&self) -> &'static str {
        self.to_cstr().to_str().unwrap()
    }
}

impl fmt::Display for JanusError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} (code: {})", self.description(), self.code())
    }
}

/// A Janus plugin result; what a plugin returns to the gateway as a direct response to a signalling message.
#[derive(Debug)]
pub struct PluginResult {
    ptr: *mut RawPluginResult,
}

impl PluginResult {
    /// Creates a new plugin result.
    pub unsafe fn new(type_: PluginResultType, text: *const c_char, content: *mut RawJanssonValue) -> Self {
        Self { ptr: ffi::plugin::janus_plugin_result_new(type_, text, content) }
    }

    /// Creates a plugin result indicating a synchronously successful request. The provided response
    /// JSON will be passed back to the client.
    pub fn ok(response: JanssonValue) -> Self {
        unsafe { Self::new(PluginResultType::JANUS_PLUGIN_OK, ptr::null(), response.into_raw()) }
    }

    /// Creates a plugin result indicating an asynchronous request in progress. If provided, the hint text
    /// will be synchronously passed back to the client in the acknowledgement.
    pub fn ok_wait(hint: Option<&'static CStr>) -> Self {
        let hint_ptr = hint.map(|x| x.as_ptr()).unwrap_or_else(ptr::null);
        unsafe { Self::new(PluginResultType::JANUS_PLUGIN_OK_WAIT, hint_ptr, ptr::null_mut()) }
    }

    /// Creates a plugin result indicating an error. The provided error text will be synchronously passed
    /// back to the client.
    pub fn error(msg: &'static CStr) -> Self {
        unsafe { Self::new(PluginResultType::JANUS_PLUGIN_ERROR, msg.as_ptr(), ptr::null_mut()) }
    }

    /// Transfers ownership of this result to the wrapped raw pointer. The consumer is responsible for calling
    /// `janus_plugin_result_destroy` on the pointer when finished.
    pub fn into_raw(self) -> *mut RawPluginResult {
        let ptr = self.ptr;
        mem::forget(self);
        ptr
    }
}

impl Deref for PluginResult {
    type Target = RawPluginResult;

    fn deref(&self) -> &RawPluginResult {
        unsafe { &*self.ptr }
    }
}

impl Drop for PluginResult {
    fn drop(&mut self) {
        unsafe { ffi::plugin::janus_plugin_result_destroy(self.ptr) }
    }
}

unsafe impl Send for PluginResult {}

#[derive(Debug)]
/// Represents metadata about this library which Janus can query at runtime.
pub struct LibraryMetadata<'a> {
    pub api_version: c_int,
    pub version: c_int,
    pub version_str: &'a CStr,
    pub description: &'a CStr,
    pub name: &'a CStr,
    pub author: &'a CStr,
    pub package: &'a CStr,
}

/// Helper macro to produce a Janus plugin instance. Should be called with
/// a `LibraryMetadata` instance and a series of exported plugin callbacks.
#[macro_export]
macro_rules! build_plugin {
    ($md:expr, $($cb:ident),*) => {{
        extern "C" fn get_api_compatibility() -> c_int { $md.api_version }
        extern "C" fn get_version() -> c_int { $md.version }
        extern "C" fn get_version_string() -> *const c_char { $md.version_str.as_ptr() }
        extern "C" fn get_description() -> *const c_char { $md.description.as_ptr() }
        extern "C" fn get_name() -> *const c_char { $md.name.as_ptr() }
        extern "C" fn get_author() -> *const c_char { $md.author.as_ptr() }
        extern "C" fn get_package() -> *const c_char { $md.package.as_ptr() }
        $crate::Plugin {
            get_api_compatibility,
            get_version,
            get_version_string,
            get_description,
            get_name,
            get_author,
            get_package,
            $($cb,)*
        }
    }}
}

/// Macro to export a Janus plugin instance from this module.
#[macro_export]
macro_rules! export_plugin {
    ($pl:expr) => {
        /// Called by Janus to create an instance of this plugin, using the provided callbacks to dispatch events.
        #[no_mangle]
        pub extern "C" fn create() -> *const $crate::Plugin { $pl }
    }
}

/// Helper macro to produce a Janus event handler instance. Should be called with
/// a `LibraryMetadata` instance and a series of exported event handler callbacks.
#[macro_export]
macro_rules! build_eventhandler {
    ($md:expr, $mask:expr, $($cb:ident),*) => {{
        extern "C" fn get_api_compatibility() -> c_int { $md.api_version }
        extern "C" fn get_version() -> c_int { $md.version }
        extern "C" fn get_version_string() -> *const c_char { $md.version_str.as_ptr() }
        extern "C" fn get_description() -> *const c_char { $md.description.as_ptr() }
        extern "C" fn get_name() -> *const c_char { $md.name.as_ptr() }
        extern "C" fn get_author() -> *const c_char { $md.author.as_ptr() }
        extern "C" fn get_package() -> *const c_char { $md.package.as_ptr() }
        $crate::EventHandler {
            events_mask: $mask,
            get_api_compatibility,
            get_version,
            get_version_string,
            get_description,
            get_name,
            get_author,
            get_package,
            $($cb,)*
        }
    }}
}

/// Macro to export a Janus event handler instance from this module.
#[macro_export]
macro_rules! export_eventhandler {
    ($evh:expr) => {
        /// Called by Janus to create an instance of this event handler, using the provided callbacks to dispatch events.
        #[no_mangle]
        pub extern "C" fn create() -> *const $crate::EventHandler { $evh }
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Error, Formatter, Show};

pub struct Tree<T> {
    pub data: T,
    pub children: Vec<Tree<T>>,
}

pub struct Zipper<T> {
    pub here: Tree<T>,
    lefts: Vec<Tree<T>>,
    rights: Vec<Tree<T>>,
    parent_path: Vec<(Vec<Tree<T>>, T, Vec<Tree<T>>)>,
}

pub enum Modified<T> {
    Old(Zipper<T>),
    New(Zipper<T>),
}

impl<T> Modified<T> {
    pub fn is_new(&self) -> bool {
        match self {
            &Modified::New(_) => true,
            _ => false,
        }
    }

    pub fn is_old(&self) -> bool {
        match self {
            &Modified::Old(_) => true,
            _ => false,
        }
    }

    pub fn unwrap(self) -> Zipper<T> {
        match self {
            Modified::New(z) => z,
            Modified::Old(z) => z,
        }
    }
}

impl<T> Tree<T> {
    pub fn new(data: T, children: Vec<Tree<T>>) -> Tree<T> {
        Tree {
            data: data,
            children: children,
        }
    }

    pub fn leaf(data: T) -> Tree<T> {
        Tree {
            data: data,
            children: Vec::new(),
        }
    }

    pub fn zipper(self) -> Zipper<T> {
        Zipper {
            lefts: Vec::new(),
            here: self,
            rights: Vec::new(),
            parent_path: Vec::new(),
        }
    }
}

impl<T: Show> Show for Tree<T> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        enum Walk<T> { Down(T), Up, };
        let mut stack = Vec::new();
        try![write!(f, "({}", self.data)];
        stack.push(Walk::Up);
        for c in self.children.iter().rev() {
            stack.push(Walk::Down(c));
        }
        loop {
            match stack.pop() {
                None => return Ok(()),
                Some(Walk::Up) => try![write!(f, ")")],
                Some(Walk::Down(t)) => {
                    try![write!(f, " ({}", t.data)];
                    stack.push(Walk::Up);
                    for c in t.children.iter().rev() {
                        stack.push(Walk::Down(c));
                    }
                },
            }
        }
    }
}

impl<T: Clone> Clone for Tree<T> {
    fn clone(&self) -> Tree<T> {
        Tree {
            data: self.data.clone(),
            children: self.children.clone(),
        }
    }

    fn clone_from(&mut self, source: &Tree<T>) {
        self.data.clone_from(&source.data);
        self.children.clone_from(&source.children);
    }
}

impl<T: PartialEq> PartialEq for Tree<T> {
    fn eq(&self, other: &Tree<T>) -> bool {
        let mut stack = Vec::new();
        stack.push((self, other));
        loop {
            match stack.pop() {
                Some((x, y)) => {
                    if x.data != y.data {
                        return false;
                    } else if x.children.len() != y.children.len() {
                        return false;
                    } else {
                        let mut xi = x.children.iter();
                        let mut yi = y.children.iter();
                        loop {
                            match (xi.next(), yi.next()) {
                                (Some(xt), Some(yt)) => stack.push((xt, yt)),
                                (None, None) => break,
                                _ => panic!("Tree corruption"),
                            }
                        }
                    }
                },
                None => return true,
            }
        }
    }
}

impl<T> Zipper<T> {
    pub fn to_root(mut self) -> Zipper<T> {
        let mut lefts = self.lefts;
        let mut here = self.here;
        let mut rights = self.rights;
        loop {
            match self.parent_path.pop() {
                None => return Zipper {
                    lefts: Vec::new(),
                    rights: Vec::new(),
                    here: here,
                    parent_path: Vec::new(),
                },
                Some((parent_lefts, parent_data, parent_rights)) => {
                    let mut new_children = Vec::with_capacity(lefts.len() + rights.len() + 1);
                    new_children.extend(lefts.into_iter());
                    new_children.push(here);
                    new_children.extend(rights.into_iter().rev());
                    here = Tree::new(parent_data, new_children);
                    lefts = parent_lefts;
                    rights = parent_rights;
                },
            }
        }
    }

    pub fn to_left(mut self) -> Modified<T> {
        let sibling = self.lefts.pop();
        if sibling.is_none() {
            Modified::Old(self)
        } else {
            self.rights.push(self.here);
            self.here = sibling.unwrap();
            Modified::New(self)
        }
    }

    pub fn to_right(mut self) -> Modified<T> {
        let sibling = self.rights.pop();
        if sibling.is_none() {
            Modified::Old(self)
        } else {
            self.lefts.push(self.here);
            self.here = sibling.unwrap();
            Modified::New(self)
        }
    }

    pub fn tree(self) -> Tree<T> {
        self.to_root().here
    }

    pub fn to_parent(mut self) -> Modified<T> {
        match self.parent_path.pop() {
            None => Modified::Old(self),
            Some((parent_lefts, parent_data, parent_rights)) => {
                let mut new_children = Vec::with_capacity(self.lefts.len() + self.rights.len() + 1);
                new_children.extend(self.lefts.into_iter());
                new_children.push(self.here);
                new_children.extend(self.rights.into_iter());
                self.lefts = parent_lefts;
                self.here = Tree::new(parent_data, new_children);
                self.rights = parent_rights;
                Modified::New(self)
            },
        }
    }

    pub fn to_first_child(self) -> Modified<T> {
        self.to_child_at(0u)
    }

    pub fn to_child_at(mut self, child_index: uint) -> Modified<T> {
        if self.here.children.len() <= child_index {
            Modified::Old(self)
        } else {
            let child = self.here.children.remove(child_index).unwrap();
            let mut lefts = Vec::with_capacity(child_index);
            let mut rights = Vec::with_capacity(self.here.children.len() - child_index);
            let mut i = self.here.children.into_iter();
            for _ in range(0, child_index) {
                lefts.push(i.next().unwrap());
            }
            for x in i.rev() {
                rights.push(x);
            }
            self.parent_path.push((self.lefts, self.here.data, self.rights));
            self.lefts = lefts;
            self.here = child;
            self.rights = rights;
            Modified::New(self)
        }
    }

    pub fn to_last_child(self) -> Modified<T> {
        if self.here.children.is_empty() {
            Modified::Old(self)
        } else {
            let child_index = self.here.children.len() - 1;
            self.to_child_at(child_index)
        }
    }

    pub fn set_tree(&mut self, here: Tree<T>) {
        self.here = here;
    }

    pub fn shrink_to_fit(&mut self) {
        self.here.children.shrink_to_fit();
        self.lefts.shrink_to_fit();
        self.rights.shrink_to_fit();
        self.parent_path.shrink_to_fit();
    }

    pub fn push_left(&mut self, sibling: Tree<T>) {
        self.lefts.push(sibling);
    }

    pub fn to_push_left(mut self, sibling: Tree<T>) -> Zipper<T> {
        self.rights.push(self.here);
        Zipper {
            lefts: self.lefts,
            here: sibling,
            rights: self.rights,
            parent_path: self.parent_path,
        }
    }

    pub fn push_right(&mut self, sibling: Tree<T>) {
        self.rights.push(sibling);
    }

    pub fn to_push_right(mut self, sibling: Tree<T>) -> Zipper<T> {
        self.lefts.push(self.here);
        Zipper {
            lefts: self.lefts,
            here: sibling,
            rights: self.rights,
            parent_path: self.parent_path,
        }
    }

    pub fn push_child_at(&mut self, index: uint, child: Tree<T>) -> bool {
        if index <= self.here.children.len() {
            self.here.children.insert(index, child);
            true
        } else {
            false
        }
    }

    pub fn push_child_front(&mut self, child: Tree<T>) {
        self.here.children.insert(0, child);
    }

    pub fn push_child_back(&mut self, child: Tree<T>) {
        self.here.children.push(child);
    }

    pub fn to_push_child_front(self, child: Tree<T>) -> Zipper<T> {
        match self.to_push_child_at(0, child) {
            Some(z) => z,
            None => panic!("Unable to add child"),
        }
    }

    pub fn to_push_child_back(self, child: Tree<T>) -> Zipper<T> {
        let target_index = self.here.children.len() - 1;
        match self.to_push_child_at(target_index, child) {
            Some(z) => z,
            None => panic!("Unable to add child"),
        }
    }

    pub fn to_push_child_at(mut self, index: uint, child: Tree<T>) -> Option<Zipper<T>> {
        if index > self.here.children.len() {
            None
        } else {
            self.parent_path.push((self.lefts, self.here.data, self.rights));
            let mut left_children = Vec::with_capacity(index);
            let mut right_children = Vec::with_capacity(self.here.children.len() - index);
            let mut i = self.here.children.into_iter();
            for _ in range(0, index) {
                left_children.push(i.next().unwrap());
            }
            for x in i {
                right_children.push(x);
            }
            Some(Zipper {
                lefts: left_children,
                here: child,
                rights: right_children,
                parent_path: self.parent_path,
            })
        }
    }

    pub fn drop_left(&mut self) -> bool {
        if self.lefts.is_empty() {
            false
        } else {
            self.lefts.pop();
            true
        }
    }

    pub fn drop_right(&mut self) -> bool {
        if self.rights.is_empty() {
            false
        } else {
            self.rights.pop();
            true
        }
    }

    pub fn make_orphan(&mut self) {
        self.lefts.clear();
        self.rights.clear();
        self.parent_path.clear();
    }

    pub fn make_leaf(&mut self) {
        self.here.children.clear();
    }

    pub fn delete(mut self) -> Option<Zipper<T>> {
        match self.rights.pop() {
            Some(new_here) => {
                self.here = new_here;
                Some(self)
            },
            None => match self.lefts.pop() {
                Some(new_here) => {
                    self.here = new_here;
                    Some(self)
                },
                None => match self.parent_path.pop() {
                    None => None,
                    Some((parent_lefts, parent_data, parent_rights)) => {
                        self.lefts = parent_lefts;
                        self.here = Tree::leaf(parent_data);
                        self.rights = parent_rights;
                        Some(self)
                    },
                },
            },
        }
    }
}

impl<T: Clone> Clone for Zipper<T> {
    fn clone(&self) -> Zipper<T> {
        Zipper {
            here: self.here.clone(),
            lefts: self.lefts.clone(),
            rights: self.rights.clone(),
            parent_path: self.parent_path.clone(),
        }
    }

    fn clone_from(&mut self, source: &Zipper<T> ) {
        self.here = source.here.clone();
        self.lefts = source.lefts.clone();
        self.rights = source.rights.clone();
        self.parent_path = source.parent_path.clone();
    }
}

impl<T: PartialEq> PartialEq for Zipper<T> {
    fn eq(&self, other: &Zipper<T>) -> bool {
        self.here == other.here
            && self.lefts == other.lefts
            && self.rights == other.rights
            && self.parent_path == other.parent_path
    }
}

#[cfg(test)]
mod tests {
    extern crate test;

    use super::Tree;

    #[test]
    fn test_new() {
        let t = Tree::new("head", vec![Tree::leaf("one"),
                                       Tree::leaf("two"),
                                       Tree::leaf("three")]);
        assert_eq!(t.data, "head");
        assert_eq!(t.children, vec![Tree::leaf("one"),
                                    Tree::leaf("two"),
                                    Tree::leaf("three")]);
    }

    #[test]
    fn test_leaf() {
        let t = Tree::leaf("asdf");
        assert_eq!(t.data, "asdf");
        assert_eq!(t.children.len(), 0);
    }

    #[test]
    fn test_trivial_tree_equality() {
        let t1 = Tree::new("head", vec![Tree::leaf("one"),
                                        Tree::leaf("two"),
                                        Tree::leaf("three")]);
        let t2 = Tree::new("head", vec![Tree::leaf("one"),
                                        Tree::leaf("two"),
                                        Tree::leaf("three")]);
        assert_eq!(t1, t2);
        assert_eq!(t1, t1);
        assert_eq!(t2, t2);
        assert!(t1 != Tree::leaf("head"));
        assert!(t1 != Tree::new("blarg", vec![Tree::leaf("one"),
                                              Tree::leaf("two"),
                                              Tree::leaf("three")]));
    }

    #[test]
    fn test_trivial_zipper_equality() {
        let z1 = Tree::new("head", vec![Tree::leaf("one"),
                                        Tree::leaf("two"),
                                        Tree::leaf("three")]).zipper();
        let z2 = Tree::new("head", vec![Tree::leaf("one"),
                                        Tree::leaf("two"),
                                        Tree::leaf("three")]).zipper();
        assert!(z1 == z2);
        assert!(z1 != Tree::leaf("head").zipper());
        assert!(z1 != Tree::new("blarg", vec![Tree::leaf("one"),
                                              Tree::leaf("two"),
                                              Tree::leaf("three")]).zipper());
    }

    #[test]
    fn test_trivial_clone() {
        let t1 = Tree::new("head", vec![Tree::leaf("one"),
                                        Tree::leaf("two"),
                                        Tree::leaf("three")]);
        assert_eq!(t1, t1.clone());
    }

    #[test]
    fn test_trivial_show() {
        let t1 = Tree::new("head", vec![Tree::leaf("one"),
                                        Tree::leaf("two"),
                                        Tree::leaf("three")]);
        assert_eq!(t1.to_string(),
                   "(head (one) (two) (three))".to_string());
    }

    #[test]
    fn test_trivial_zipping_1() {
        let mut z = Tree::leaf("head").zipper();
        assert_eq!(z.here.to_string(), "(head)".to_string());
        assert_eq!(z.clone().to_root().here.to_string(),
                   "(head)".to_string());
        z = z.to_push_child_front(Tree::leaf("two"));
        assert_eq!(z.here.to_string(), "(two)".to_string());
        assert_eq!(z.clone().to_root().here.to_string(),
                   "(head (two))".to_string());
        z = z.to_push_left(Tree::leaf("one"));
        assert_eq!(z.here.to_string(), "(one)".to_string());
        assert_eq!(z.clone().to_root().here.to_string(),
                   "(head (one) (two))".to_string());
        z = match z.to_right() {
            x => {
                assert!(x.is_new());
                x.unwrap()
            }
        };
        assert_eq!(z.clone().to_root().here.to_string(),
                   "(head (one) (two))".to_string());
    }

    #[test]
    fn test_trivial_zipping_2() {
        let mut z = Tree::leaf("head").zipper();
        z = z.to_push_child_front(Tree::leaf("two"));
        assert_eq!(z.here.to_string(), "(two)".to_string());
        z = z.to_push_left(Tree::leaf("one"));
        assert_eq!(z.here.to_string(), "(one)".to_string());
        z = z.to_right().unwrap();
        z.push_right(Tree::leaf("three"));
        assert_eq!(z.here.to_string(), "(two)".to_string());
        assert_eq!(z.clone().to_root().here.to_string(),
                   "(head (one) (two) (three))".to_string());

        z = match z.to_right() {
            x => {
                assert!(x.is_new());
                x.unwrap()
            }
        };
        assert_eq!(z.here.to_string(), "(three)".to_string());
        assert_eq!(z.clone().to_root().here.to_string(),
                   "(head (one) (two) (three))".to_string());

        z = match z.to_right() {
            x => {
                assert!(x.is_old());
                x.unwrap()
            }
        };

        z = match z.to_left() {
            x => {
                assert!(x.is_new());
                x.unwrap()
            }
        };
        assert_eq!(z.here.to_string(), "(two)".to_string());
        assert_eq!(z.clone().to_root().here.to_string(),
                   "(head (one) (two) (three))".to_string());

        z = match z.to_left() {
            x => {
                assert!(x.is_new());
                x.unwrap()
            }
        };
        assert_eq!(z.here.to_string(), "(one)".to_string());
        assert_eq!(z.clone().to_root().here.to_string(),
                   "(head (one) (two) (three))".to_string());

        z = match z.to_left() {
            x => {
                assert!(x.is_old());
                x.unwrap()
            }
        };
        assert_eq!(z.here.to_string(), "(one)".to_string());
        assert_eq!(z.clone().to_root().here.to_string(),
                   "(head (one) (two) (three))".to_string());
    }
}
<commit_msg>Trying to zipper into tree navigation and tree editing.<commit_after>use std::borrow::Borrow;
use std::cell::RefCell;
use std::fmt::{Debug, Error, Formatter};
use std::num::{Int, SignedInt};

pub struct Tree<T> {
    data: T,
    children: Vec<Tree<T>>,
}

struct TraversalCell<'a, T: 'a> {
    tree: &'a Tree<T>,
    index: usize,
}

pub struct Navigator<'a, T: 'a> {
    here: &'a Tree<T>,
    path: Vec<TraversalCell<'a, T>>,
}

impl<T> Tree<T> {
    pub fn leaf(data: T) -> Tree<T> {
        Tree {
            data: data,
            children: Vec::new(),
        }
    }

    pub fn data<'s>(&'s self) -> &'s T {
        &self.data
    }

    pub fn data_mut<'s>(&'s mut self) -> &'s mut T {
        &mut self.data
    }

    pub fn children<'s>(&'s self) -> &'s [Tree<T>] {
        self.children.as_slice()
    }

    pub fn children_mut<'s>(&'s mut self) -> &'s mut [Tree<T>] {
        self.children.as_mut_slice()
    }
}

#[macro_export]
macro_rules! tree {
    ($data:expr) => ($crate::Tree::leaf($data));
    ($data:expr, [$($first:tt)*] $(,[$($rest:tt)*])*) =>
        ($crate::Tree { data: $data,
                        children: vec![tree![$($first)*]
                                       $(,tree![$($rest)*])*] });
}

// impl<T: Show> Show for Tree<T> {
//     fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
//         enum Walk<T> { Down(T), Up, };
//         let mut stack = Vec::new();
//         try![write!(f, "({}", self.data)];
//         stack.push(Walk::Up);
//         for c in self.children.iter().rev() {
//             stack.push(Walk::Down(c));
//         }
//         loop {
//             match stack.pop() {
//                 None => return Ok(()),
//                 Some(Walk::Up) => try![write!(f, ")")],
//                 Some(Walk::Down(t)) => {
//                     try![write!(f, " ({}", t.data)];
//                     stack.push(Walk::Up);
//                     for c in t.children.iter().rev() {
//                         stack.push(Walk::Down(c));
//                     }
//                 },
//             }
//         }
//     }
// }

impl<T: Clone> Clone for Tree<T> {
    fn clone(&self) -> Tree<T> {
        Tree {
            data: self.data.clone(),
            children: self.children.clone(),
        }
    }

    fn clone_from(&mut self, source: &Tree<T>) {
        self.data.clone_from(&source.data);
        self.children.clone_from(&source.children);
    }
}

impl<T: PartialEq> PartialEq for Tree<T> {
    fn eq(&self, other: &Tree<T>) -> bool {
        let mut stack = Vec::new();
        stack.push((self, other));
        loop {
            match stack.pop() {
                Some((x, y)) => {
                    if x.data != y.data {
                        return false;
                    } else if x.children.len() != y.children.len() {
                        return false;
                    } else {
                        let mut xi = x.children.iter();
                        let mut yi = y.children.iter();
                        loop {
                            match (xi.next(), yi.next()) {
                                (Some(xt), Some(yt)) => stack.push((xt, yt)),
                                (None, None) => break,
                                _ => panic!("Tree corruption"),
                            }
                        }
                    }
                },
                None => return true,
            }
        }
    }
}

impl<'a, T: 'a> Navigator<'a, T> {
    pub fn is_root(&self) -> bool {
        self.path.is_empty()
    }

    pub fn is_leaf(&self) -> bool {
        self.here.children.is_empty()
    }

    pub fn to_parent(&mut self) {
        loop {
            match self.path.pop() {
                None => return,
                Some(traversal) => {
                    self.here = &traversal.tree.children[traversal.index]
                },
            }
        }
    }

    pub fn tree<'s>(&'s self) -> &'s Tree<T> {
        &self.here
    }

    pub fn seek_sibling(&mut self, offset: isize) {
        assert![!self.is_root()];
        if offset == 0 {
            return;
        }
        let mut cell = self.path.pop().expect("tree corruption");
        let offset_abs = offset.abs();
        let new_index =
            if offset_abs < 0 {
                // offset is Int::min_value().
                cell.index
                    .checked_sub(1).expect("index undeflow")
                    .checked_sub((offset_abs + 1isize).abs() as usize).expect("index underflow")
            } else {
                if offset < 0 {
                    cell.index.checked_sub(offset_abs as usize).expect("index underflow")
                } else {
                    cell.index.checked_add(offset_abs as usize).expect("index overflow")
                }
            };
        assert![new_index < cell.tree.children.len(),
                "sibling index {} out of range (only {} siblings)",
                new_index, cell.tree.children.len()];
        self.here = &cell.tree.children[new_index];
        cell.index = new_index;
        self.path.push(cell);
    }

    pub fn seek_child(&mut self, child_index: usize) {
        assert![child_index < self.here.children.len(),
                "child index {} out of range (only {} children)",
                child_index, self.here.children.len()];
        self.path.push(TraversalCell { tree: self.here,
                                       index: child_index });
        self.here = &self.here.children[child_index];
    }
}

impl<'a, T: 'a> Borrow<Tree<T>> for Navigator<'a, T> {
    fn borrow(&self) -> &Tree<T> {
        self.here
    }
}
<|endoftext|>


<commit_before>//! Does all the magic to have you potentially long output piped through the
//! external pager. Similar to what git does for its output.
//!
//! Quick Start
//!
//! ```
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::new().setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! Under the hood this forks the current process, connects child' stdout
//! to parent's stdin, and then replaces the parent with the pager of choice
//! (environment variable PAGER). The child just continues as normal.
//!
//! You can control pager to a limited degree. For example you can change the
//! environment variable used for finding pager executable.
//!
//! ```
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::env("MY_PAGER").setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! If no PAGER is found `setup()` does nothing and your executable keeps
//! running as usual. `Pager` cleans after itself and doesn't leak resources in
//! case of setup failure.
//!

extern crate libc;

use std::env;
use std::ffi::CString;
use std::ptr;
use std::os::unix::ffi::OsStrExt;

const DEFAULT_PAGER_ENV: &'static str = "PAGER";

#[derive(Debug, Default)]
pub struct Pager {
    env: String,
    ok: bool,
}

impl Pager {
    pub fn new() -> Self {
        Pager {
            env: String::from(DEFAULT_PAGER_ENV),
            ok: true,
        }
    }

    pub fn env(env: &str) -> Self {
        Pager {
            env: String::from(env),
            ok: true,
        }
    }

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

    pub fn setup(&mut self) {
        if let Some(pager) = getenv(&self.env) {
            let (pager_stdin, main_stdout) = pipe();
            let pid = fork();
            match pid {
                -1 => {
                    // Fork failed
                    close(pager_stdin);
                    close(main_stdout);
                    self.ok = false
                }
                0 => {
                    // I am child
                    dup2(main_stdout, libc::STDOUT_FILENO);
                    close(pager_stdin);
                }
                _ => {
                    // I am parent
                    let argv = vec![pager.as_ptr(), ptr::null()];
                    dup2(pager_stdin, libc::STDIN_FILENO);
                    close(main_stdout);
                    execvp(argv);
                }
            }
        }
    }
}

// In C this would be simple getenv(). Not in Rust though
fn getenv(var: &str) -> Option<CString> {
    let value = env::var_os(&var).unwrap();
    let value = value.as_os_str().as_bytes();
    let value = CString::new(value);
    value.ok()
    // let to_bytes = |x: &OsString| x.as_os_str().as_bytes();
    // let to_bytes = |x: &OsString| x.into::<Vec<u8>>();
    // env::var_os(&self.env).map(to_bytes).and_then(|x| CString::new(x).ok())
}

// Helper wrappers around libc::* API
fn fork() -> libc::pid_t {
    unsafe { libc::fork() }
}

fn execvp(argv: Vec<*const libc::c_char>) {
    assert!(unsafe { libc::execvp(argv[0], argv.as_ptr()) } > -1);
}

fn dup2(fd1: i32, fd2: i32) {
    assert!(unsafe { libc::dup2(fd1, fd2) } > -1);
}

fn close(fd: i32) {
    assert_eq!(unsafe { libc::close(fd) }, 0);
}

fn pipe() -> (i32, i32) {
    let mut fds = [0; 2];
    assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
    (fds[0], fds[1])
}
<commit_msg>Fix to make doctest work<commit_after>//! Does all the magic to have you potentially long output piped through the
//! external pager. Similar to what git does for its output.
//!
//! Quick Start
//!
//! ```
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::new().setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! Under the hood this forks the current process, connects child' stdout
//! to parent's stdin, and then replaces the parent with the pager of choice
//! (environment variable PAGER). The child just continues as normal.
//!
//! You can control pager to a limited degree. For example you can change the
//! environment variable used for finding pager executable.
//!
//! ```
//! extern crate pager;
//! use pager::Pager;
//! fn main() {
//!     Pager::env("MY_PAGER").setup();
//!     // The rest of your program goes here
//! }
//! ```
//!
//! If no PAGER is found `setup()` does nothing and your executable keeps
//! running as usual. `Pager` cleans after itself and doesn't leak resources in
//! case of setup failure.
//!

extern crate libc;

use std::env;
use std::ffi::CString;
use std::ptr;
use std::os::unix::ffi::OsStrExt;

const DEFAULT_PAGER_ENV: &'static str = "PAGER";

#[derive(Debug, Default)]
pub struct Pager {
    env: String,
    ok: bool,
}

impl Pager {
    pub fn new() -> Self {
        Pager {
            env: String::from(DEFAULT_PAGER_ENV),
            ok: true,
        }
    }

    pub fn env(env: &str) -> Self {
        Pager {
            env: String::from(env),
            ok: true,
        }
    }

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

    pub fn setup(&mut self) {
        if let Some(pager) = getenv(&self.env) {
            let (pager_stdin, main_stdout) = pipe();
            let pid = fork();
            match pid {
                -1 => {
                    // Fork failed
                    close(pager_stdin);
                    close(main_stdout);
                    self.ok = false
                }
                0 => {
                    // I am child
                    dup2(main_stdout, libc::STDOUT_FILENO);
                    close(pager_stdin);
                }
                _ => {
                    // I am parent
                    let argv = vec![pager.as_ptr(), ptr::null()];
                    dup2(pager_stdin, libc::STDIN_FILENO);
                    close(main_stdout);
                    execvp(argv);
                }
            }
        }
    }
}

// In C this would be simple getenv(). Not in Rust though
fn getenv(var: &str) -> Option<CString> {
    if let Some(value) = env::var_os(var) {
        let value = value.as_os_str().as_bytes();
        let value = CString::new(value);
        value.ok()
    } else {
        None
    }
    // let to_bytes = |x: &OsString| x.as_os_str().as_bytes();
    // let to_bytes = |x: &OsString| x.into::<Vec<u8>>();
    // env::var_os(&self.env).map(to_bytes).and_then(|x| CString::new(x).ok())
}

// Helper wrappers around libc::* API
fn fork() -> libc::pid_t {
    unsafe { libc::fork() }
}

fn execvp(argv: Vec<*const libc::c_char>) {
    assert!(unsafe { libc::execvp(argv[0], argv.as_ptr()) } > -1);
}

fn dup2(fd1: i32, fd2: i32) {
    assert!(unsafe { libc::dup2(fd1, fd2) } > -1);
}

fn close(fd: i32) {
    assert_eq!(unsafe { libc::close(fd) }, 0);
}

fn pipe() -> (i32, i32) {
    let mut fds = [0; 2];
    assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
    (fds[0], fds[1])
}
<|endoftext|>