<commit_before>use std::fmt;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::collections::HashMap;

extern crate rustc_serialize;
use self::rustc_serialize::json::{as_json, Json, Object};

#[derive(Eq, PartialEq, PartialOrd, Ord, Debug)]
pub struct Location {
    pub lineno: u32,
    pub col_start: u32,
    pub col_end: u32,
}

impl fmt::Display for Location {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, r#""loc":"{:05}:{}-{}""#, self.lineno, self.col_start, self.col_end)
    }
}

#[derive(Eq, PartialEq, PartialOrd, Ord, Debug)]
pub struct LineRange {
    pub start_lineno: u32,
    pub end_lineno: u32,
}

#[derive(Debug)]
pub struct WithLocation<T> {
    pub data: T,
    pub loc: Location,
}

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum AnalysisKind {
    Use,
    Def,
    Assign,
    Decl,
    Idl,
}

impl fmt::Display for AnalysisKind {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let str = match self {
            AnalysisKind::Use => "use",
            AnalysisKind::Def => "def",
            AnalysisKind::Assign => "assign",
            AnalysisKind::Decl => "decl",
            AnalysisKind::Idl => "idl",
        };
        formatter.write_str(str)
    }
}

#[derive(Debug)]
pub struct AnalysisTarget {
    pub kind: AnalysisKind,
    pub pretty: String,
    pub sym: String,
    pub context: String,
    pub contextsym: String,
    pub peek_range: LineRange,
}

impl fmt::Display for AnalysisTarget {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter,
               r#""target":1,"kind":"{}","pretty":{},"sym":{}"#,
               self.kind,
               as_json(&self.pretty),
               as_json(&self.sym))?;
        if !self.context.is_empty() {
            write!(formatter, r#","context":{}"#, as_json(&self.context))?;
        }
        if !self.contextsym.is_empty() {
            write!(formatter, r#","contextsym":{}"#, as_json(&self.contextsym))?;
        }
        if self.peek_range.start_lineno != 0 || self.peek_range.end_lineno != 0 {
            write!(formatter,
                   r#","peekRange":"{}-{}""#,
                   self.peek_range.start_lineno,
                   self.peek_range.end_lineno)?;
        }
        Ok(())
    }
}

impl fmt::Display for WithLocation<AnalysisTarget> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{{{},{}}}", self.loc, self.data)
    }
}

#[derive(Debug)]
pub struct AnalysisSource {
    pub syntax: Vec<String>,
    pub pretty: String,
    pub sym: Vec<String>,
    pub no_crossref: bool,
}

impl fmt::Display for AnalysisSource {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter,
               r#""source":1,"syntax":{},"pretty":{},"sym":{}"#,
               as_json(&self.syntax.join(",")),
               as_json(&self.pretty),
               as_json(&self.sym.join(",")))?;
        if self.no_crossref {
            write!(formatter, r#","no_crossref":1"#)?;
        }
        Ok(())
    }
}

impl fmt::Display for WithLocation<AnalysisSource> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{{{},{}}}", self.loc, self.data)
    }
}

impl fmt::Display for WithLocation<Vec<AnalysisSource>> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let locstr = format!("{}", self.loc);
        for src in &self.data {
            writeln!(formatter, "{{{},{}}}", locstr, src)?;
        }
        Ok(())
    }
}

fn parse_location(loc: &str) -> Location {
    let v : Vec<&str> = loc.split(":").collect();
    let lineno = v[0].parse::<u32>().unwrap();
    let (col_start, col_end) = if v[1].contains("-") {
        let v : Vec<&str> = v[1].split("-").collect();
        (v[0], v[1])
    } else {
        (v[1], v[1])
    };
    let col_start = col_start.parse::<u32>().unwrap();
    let col_end = col_end.parse::<u32>().unwrap();
    Location { lineno: lineno, col_start: col_start, col_end: col_end }
}

fn parse_line_range(range: &str) -> LineRange {
    let v : Vec<&str> = range.split("-").collect();
    let start_lineno = v[0].parse::<u32>().unwrap();
    let end_lineno = v[1].parse::<u32>().unwrap();
    LineRange { start_lineno: start_lineno, end_lineno: end_lineno }
}

pub fn read_analysis<T>(filename: &str, filter: &Fn(&Object) -> Option<T>) -> Vec<WithLocation<Vec<T>>> {
    let file = match File::open(filename) {
        Ok(f) => f,
        Err(_) => return vec![],
    };
    let reader = BufReader::new(&file);
    let mut result = Vec::new();
    let mut lineno = 1;
    for line in reader.lines() {
        let line = line.unwrap();
        let data = Json::from_str(&line);
        let data = match data {
            Ok(data) => data,
            Err(e) => panic!("error {} on line {}: {}", e, lineno, &line),
        };
        lineno += 1;
        let obj = data.as_object().unwrap();
        match filter(obj) {
            Some(v) => {
                let loc = parse_location(obj.get("loc").unwrap().as_string().unwrap());
                result.push(WithLocation { data: v, loc: loc })
            }
            None => {}
        }
    }

    result.sort_by(|x1, x2| {
        x1.loc.cmp(&x2.loc)
    });

    let mut result2 = Vec::new();
    let mut last_loc = None;
    let mut last_vec = Vec::new();
    for r in result {
        match last_loc {
            Some(ll) => {
                if ll == r.loc {
                    last_loc = Some(ll);
                } else {
                    result2.push(WithLocation { loc: ll, data: last_vec });
                    last_vec = Vec::new();
                    last_loc = Some(r.loc);
                }
            },
            None => {
                last_loc = Some(r.loc);
            }
        }
        last_vec.push(r.data);
    }

    match last_loc {
        Some(ll) => result2.push(WithLocation { loc: ll, data: last_vec }),
        None => {},
    }

    result2
}

pub fn read_target(obj : &Object) -> Option<AnalysisTarget> {
    if !obj.contains_key("target") {
        return None;
    }

    let kindstr = obj.get("kind").unwrap().as_string().unwrap();
    let kind = match kindstr {
        "use" => AnalysisKind::Use,
        "def" => AnalysisKind::Def,
        "assign" => AnalysisKind::Assign,
        "decl" => AnalysisKind::Decl,
        "idl" => AnalysisKind::Idl,
        _ => panic!("bad target kind")
    };

    let pretty = match obj.get("pretty") {
        Some(json) => json.as_string().unwrap().to_string(),
        None => "".to_string()
    };
    let context = match obj.get("context") {
        Some(json) => json.as_string().unwrap().to_string(),
        None => "".to_string()
    };
    let contextsym = match obj.get("contextsym") {
        Some(json) => json.as_string().unwrap().to_string(),
        None => "".to_string()
    };
    let peek_range = match obj.get("peekRange") {
        Some(json) => parse_line_range(json.as_string().unwrap()),
        None => LineRange { start_lineno: 0, end_lineno: 0 }
    };
    let sym = obj.get("sym").unwrap().as_string().unwrap().to_string();

    Some(AnalysisTarget { kind: kind, pretty: pretty, sym: sym, context: context,
                          contextsym: contextsym, peek_range: peek_range })
}

pub fn read_source(obj : &Object) -> Option<AnalysisSource> {
    if !obj.contains_key("source") {
        return None;
    }

    let syntax = match obj.get("syntax") {
        Some(json) => json.as_string().unwrap().to_string(),
        None => "".to_string()
    };
    let mut syntax : Vec<String> = syntax.split(',').map(str::to_string).collect();
    syntax.sort();
    syntax.dedup();

    let pretty = match obj.get("pretty") {
        Some(json) => json.as_string().unwrap().to_string(),
        None => "".to_string()
    };
    let mut sym : Vec<String> = obj.get("sym").unwrap().as_string().unwrap().to_string().split(',').map(str::to_string).collect();
    sym.sort();
    sym.dedup();

    let no_crossref = match obj.get("no_crossref") {
        Some(_) => true,
        None => false,
    };

    Some(AnalysisSource { pretty: pretty, sym: sym, syntax: syntax, no_crossref: no_crossref })
}

pub struct Jump {
    pub id: String,
    pub path: String,
    pub lineno: u64,
    pub pretty: String,
}

pub fn read_jumps(filename: &str) -> HashMap<String, Jump> {
    let file = File::open(filename).unwrap();
    let reader = BufReader::new(&file);
    let mut result = HashMap::new();
    let mut lineno = 1;
    for line in reader.lines() {
        let line = line.unwrap();
        let data = Json::from_str(&line);
        let data = match data {
            Ok(data) => data,
            Err(_) => panic!("error on line {}: {}", lineno, &line),
        };
        lineno += 1;

        let array = data.as_array().unwrap();
        let id = array[0].as_string().unwrap().to_string();
        let data = Jump {
            id: id.clone(),
            path: array[1].as_string().unwrap().to_string(),
            lineno: array[2].as_u64().unwrap(),
            pretty: array[3].as_string().unwrap().to_string(),
        };

        result.insert(id, data);
    }
    result
}
<commit_msg>Add a read_analyses that slurps multiple files.<commit_after>use std::fmt;
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::collections::HashMap;

extern crate rustc_serialize;
use self::rustc_serialize::json::{as_json, Json, Object};

#[derive(Eq, PartialEq, PartialOrd, Ord, Debug)]
pub struct Location {
    pub lineno: u32,
    pub col_start: u32,
    pub col_end: u32,
}

impl fmt::Display for Location {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, r#""loc":"{:05}:{}-{}""#, self.lineno, self.col_start, self.col_end)
    }
}

#[derive(Eq, PartialEq, PartialOrd, Ord, Debug)]
pub struct LineRange {
    pub start_lineno: u32,
    pub end_lineno: u32,
}

#[derive(Debug)]
pub struct WithLocation<T> {
    pub data: T,
    pub loc: Location,
}

#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum AnalysisKind {
    Use,
    Def,
    Assign,
    Decl,
    Idl,
}

impl fmt::Display for AnalysisKind {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let str = match self {
            AnalysisKind::Use => "use",
            AnalysisKind::Def => "def",
            AnalysisKind::Assign => "assign",
            AnalysisKind::Decl => "decl",
            AnalysisKind::Idl => "idl",
        };
        formatter.write_str(str)
    }
}

#[derive(Debug)]
pub struct AnalysisTarget {
    pub kind: AnalysisKind,
    pub pretty: String,
    pub sym: String,
    pub context: String,
    pub contextsym: String,
    pub peek_range: LineRange,
}

impl fmt::Display for AnalysisTarget {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter,
               r#""target":1,"kind":"{}","pretty":{},"sym":{}"#,
               self.kind,
               as_json(&self.pretty),
               as_json(&self.sym))?;
        if !self.context.is_empty() {
            write!(formatter, r#","context":{}"#, as_json(&self.context))?;
        }
        if !self.contextsym.is_empty() {
            write!(formatter, r#","contextsym":{}"#, as_json(&self.contextsym))?;
        }
        if self.peek_range.start_lineno != 0 || self.peek_range.end_lineno != 0 {
            write!(formatter,
                   r#","peekRange":"{}-{}""#,
                   self.peek_range.start_lineno,
                   self.peek_range.end_lineno)?;
        }
        Ok(())
    }
}

impl fmt::Display for WithLocation<AnalysisTarget> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{{{},{}}}", self.loc, self.data)
    }
}

#[derive(Debug)]
pub struct AnalysisSource {
    pub syntax: Vec<String>,
    pub pretty: String,
    pub sym: Vec<String>,
    pub no_crossref: bool,
}

impl fmt::Display for AnalysisSource {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter,
               r#""source":1,"syntax":{},"pretty":{},"sym":{}"#,
               as_json(&self.syntax.join(",")),
               as_json(&self.pretty),
               as_json(&self.sym.join(",")))?;
        if self.no_crossref {
            write!(formatter, r#","no_crossref":1"#)?;
        }
        Ok(())
    }
}

impl fmt::Display for WithLocation<AnalysisSource> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{{{},{}}}", self.loc, self.data)
    }
}

impl fmt::Display for WithLocation<Vec<AnalysisSource>> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let locstr = format!("{}", self.loc);
        for src in &self.data {
            writeln!(formatter, "{{{},{}}}", locstr, src)?;
        }
        Ok(())
    }
}

fn parse_location(loc: &str) -> Location {
    let v : Vec<&str> = loc.split(":").collect();
    let lineno = v[0].parse::<u32>().unwrap();
    let (col_start, col_end) = if v[1].contains("-") {
        let v : Vec<&str> = v[1].split("-").collect();
        (v[0], v[1])
    } else {
        (v[1], v[1])
    };
    let col_start = col_start.parse::<u32>().unwrap();
    let col_end = col_end.parse::<u32>().unwrap();
    Location { lineno: lineno, col_start: col_start, col_end: col_end }
}

fn parse_line_range(range: &str) -> LineRange {
    let v : Vec<&str> = range.split("-").collect();
    let start_lineno = v[0].parse::<u32>().unwrap();
    let end_lineno = v[1].parse::<u32>().unwrap();
    LineRange { start_lineno: start_lineno, end_lineno: end_lineno }
}

pub fn read_analysis<T>(filename: &str, filter: &Fn(&Object) -> Option<T>) -> Vec<WithLocation<Vec<T>>> {
    read_analyses(&vec![filename], filter)
}

pub fn read_analyses<T>(filenames: &[&str], filter: &Fn(&Object) -> Option<T>) -> Vec<WithLocation<Vec<T>>> {
    let mut result = Vec::new();
    for filename in filenames {
        let file = match File::open(filename) {
            Ok(f) => f,
            Err(_) => continue,
        };
        let reader = BufReader::new(&file);
        let mut lineno = 1;
        for line in reader.lines() {
            let line = line.unwrap();
            let data = Json::from_str(&line);
            let data = match data {
                Ok(data) => data,
                Err(e) => panic!("error {} on file {} line {}: {}", e, filename, lineno, &line),
            };
            lineno += 1;
            let obj = data.as_object().unwrap();
            match filter(obj) {
                Some(v) => {
                    let loc = parse_location(obj.get("loc").unwrap().as_string().unwrap());
                    result.push(WithLocation { data: v, loc: loc })
                }
                None => {}
            }
        }
    }

    result.sort_by(|x1, x2| {
        x1.loc.cmp(&x2.loc)
    });

    let mut result2 = Vec::new();
    let mut last_loc = None;
    let mut last_vec = Vec::new();
    for r in result {
        match last_loc {
            Some(ll) => {
                if ll == r.loc {
                    last_loc = Some(ll);
                } else {
                    result2.push(WithLocation { loc: ll, data: last_vec });
                    last_vec = Vec::new();
                    last_loc = Some(r.loc);
                }
            },
            None => {
                last_loc = Some(r.loc);
            }
        }
        last_vec.push(r.data);
    }

    match last_loc {
        Some(ll) => result2.push(WithLocation { loc: ll, data: last_vec }),
        None => {},
    }

    result2
}

pub fn read_target(obj : &Object) -> Option<AnalysisTarget> {
    if !obj.contains_key("target") {
        return None;
    }

    let kindstr = obj.get("kind").unwrap().as_string().unwrap();
    let kind = match kindstr {
        "use" => AnalysisKind::Use,
        "def" => AnalysisKind::Def,
        "assign" => AnalysisKind::Assign,
        "decl" => AnalysisKind::Decl,
        "idl" => AnalysisKind::Idl,
        _ => panic!("bad target kind")
    };

    let pretty = match obj.get("pretty") {
        Some(json) => json.as_string().unwrap().to_string(),
        None => "".to_string()
    };
    let context = match obj.get("context") {
        Some(json) => json.as_string().unwrap().to_string(),
        None => "".to_string()
    };
    let contextsym = match obj.get("contextsym") {
        Some(json) => json.as_string().unwrap().to_string(),
        None => "".to_string()
    };
    let peek_range = match obj.get("peekRange") {
        Some(json) => parse_line_range(json.as_string().unwrap()),
        None => LineRange { start_lineno: 0, end_lineno: 0 }
    };
    let sym = obj.get("sym").unwrap().as_string().unwrap().to_string();

    Some(AnalysisTarget { kind: kind, pretty: pretty, sym: sym, context: context,
                          contextsym: contextsym, peek_range: peek_range })
}

pub fn read_source(obj : &Object) -> Option<AnalysisSource> {
    if !obj.contains_key("source") {
        return None;
    }

    let syntax = match obj.get("syntax") {
        Some(json) => json.as_string().unwrap().to_string(),
        None => "".to_string()
    };
    let mut syntax : Vec<String> = syntax.split(',').map(str::to_string).collect();
    syntax.sort();
    syntax.dedup();

    let pretty = match obj.get("pretty") {
        Some(json) => json.as_string().unwrap().to_string(),
        None => "".to_string()
    };
    let mut sym : Vec<String> = obj.get("sym").unwrap().as_string().unwrap().to_string().split(',').map(str::to_string).collect();
    sym.sort();
    sym.dedup();

    let no_crossref = match obj.get("no_crossref") {
        Some(_) => true,
        None => false,
    };

    Some(AnalysisSource { pretty: pretty, sym: sym, syntax: syntax, no_crossref: no_crossref })
}

pub struct Jump {
    pub id: String,
    pub path: String,
    pub lineno: u64,
    pub pretty: String,
}

pub fn read_jumps(filename: &str) -> HashMap<String, Jump> {
    let file = File::open(filename).unwrap();
    let reader = BufReader::new(&file);
    let mut result = HashMap::new();
    let mut lineno = 1;
    for line in reader.lines() {
        let line = line.unwrap();
        let data = Json::from_str(&line);
        let data = match data {
            Ok(data) => data,
            Err(_) => panic!("error on line {}: {}", lineno, &line),
        };
        lineno += 1;

        let array = data.as_array().unwrap();
        let id = array[0].as_string().unwrap().to_string();
        let data = Jump {
            id: id.clone(),
            path: array[1].as_string().unwrap().to_string(),
            lineno: array[2].as_u64().unwrap(),
            pretty: array[3].as_string().unwrap().to_string(),
        };

        result.insert(id, data);
    }
    result
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{config::CargoConfig, utils::project_root, Result};
use anyhow::anyhow;
use log::{info, warn};
use std::{
    env,
    ffi::{OsStr, OsString},
    path::Path,
    process::{Command, Output, Stdio},
    time::Instant,
};

const RUST_TOOLCHAIN_VERSION: &str = include_str!("../../../rust-toolchain");
const RUSTUP_TOOLCHAIN: &str = "RUSTUP_TOOLCHAIN";

pub struct Cargo {
    inner: Command,
    pass_through_args: Vec<OsString>,
    env_additions: Vec<(OsString, OsString)>,
}

impl Cargo {
    pub fn new<S: AsRef<OsStr>>(cargo_config: &CargoConfig, command: S) -> Self {
        // run rustup to find correct toolchain
        let output = Command::new("rustup")
            .arg("which")
            .arg("--toolchain")
            .arg(&cargo_config.toolchain)
            .arg("cargo")
            .output()
            .expect("failed to execute rustup which");
        let (cargo_binary, cargo_flags) = if output.status.success() {
            (
                String::from_utf8(output.stdout)
                    .expect("error parsing rustup which output into utf8"),
                &cargo_config.flags,
            )
        } else {
            println!(
                "WARN: Rust toolchain {} not installed; falling back to legacy Cargo resolver.",
                cargo_config.toolchain,
            );
            println!(
                "WARN: Run `rustup toolchain install {}` to use the new resolver.",
                cargo_config.toolchain,
            );
            ("cargo".to_string(), &None)
        };

        println!(
            "cargo_binary = {}, cargo_flags = {:?}",
            cargo_binary, cargo_flags
        );

        let mut inner = Command::new(str::trim(&cargo_binary));
        if let Some(flags) = &cargo_flags {
            inner.arg(&flags);
        }

        // The environment is inherited for child processes so we only need to set RUSTUP_TOOLCHAIN
        // if it isn't already present in the environment
        if env::var_os(RUSTUP_TOOLCHAIN).is_none() {
            inner.env(RUSTUP_TOOLCHAIN, RUST_TOOLCHAIN_VERSION);
        }

        inner.arg(command);
        Self {
            inner,
            pass_through_args: Vec::new(),
            env_additions: Vec::new(),
        }
    }

    pub fn all(&mut self) -> &mut Self {
        self.inner.arg("--all");
        self
    }

    pub fn workspace(&mut self) -> &mut Self {
        self.inner.arg("--workspace");
        self
    }

    pub fn all_targets(&mut self) -> &mut Self {
        self.inner.arg("--all-targets");
        self
    }

    pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Self {
        self.inner.current_dir(dir);
        self
    }

    pub fn packages<I, S>(&mut self, packages: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for p in packages {
            self.inner.arg("--package");
            self.inner.arg(p);
        }
        self
    }

    pub fn exclusions<I, S>(&mut self, exclusions: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for e in exclusions {
            self.inner.arg("--exclude");
            self.inner.arg(e);
        }
        self
    }

    /// Adds a series of arguments to x's target command.
    pub fn args<I, S>(&mut self, args: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        self.inner.args(args);
        self
    }

    /// Adds an argument to x's target command.
    #[allow(dead_code)]
    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
        self.inner.arg(arg);
        self
    }

    /// Adds "Pass Through" arguments to x's target command.
    /// Pass through arguments appear after a double dash " -- " and may
    /// not be handled/checked by x's target command itself, but an underlying executable.
    pub fn pass_through<I, S>(&mut self, args: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for a in args {
            self.pass_through_args.push(a.as_ref().to_owned());
        }
        self
    }

    /// Passes extra environment variables to x's target command.
    pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
    where
        I: IntoIterator<Item = (K, V)>,
        K: AsRef<OsStr>,
        V: AsRef<OsStr>,
    {
        for (key, val) in vars {
            self.env(key, val);
        }
        self
    }

    /// Passes an extra environment variable to x's target command.
    pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
    where
        K: AsRef<OsStr>,
        V: AsRef<OsStr>,
    {
        self.env_additions
            .push((key.as_ref().to_os_string(), val.as_ref().to_os_string()));
        self
    }

    pub fn run(&mut self) -> Result<()> {
        self.inner.stdout(Stdio::inherit()).stderr(Stdio::inherit());
        self.do_run(true).map(|_| ())
    }

    /// Runs this command, capturing the standard output into a `Vec<u8>`.
    /// No logging/timing will be displayed as the result of this call from x.
    pub fn run_with_output(&mut self) -> Result<Vec<u8>> {
        self.inner.stderr(Stdio::inherit());
        // Since system out hijacked don't log for this command
        self.do_run(false).map(|o| o.stdout)
    }

    /// Internal run command, where the magic happens.
    /// If log is true, any environment variable overrides will be logged, the full command will be logged,
    /// and after the command's output reaches stdout, the command will be printed again along with the time took
    /// to process the command (wallclock) in ms.
    fn do_run(&mut self, log: bool) -> Result<Output> {
        // these arguments are passed through cargo/x to underlying executable (test, clippy, etc)
        if !self.pass_through_args.is_empty() {
            self.inner.arg("--").args(&self.pass_through_args);
        }

        // once all the arguments are added to the command we can log it.
        if log {
            self.env_additions
                .iter()
                .for_each(|t| info!("Env {:?}: {:?}", t.0, t.1));
            info!("Executing: {:?}", &self.inner);
        }
        self.inner
            .envs(self.env_additions.iter().map(|(k, v)| (k, v)));
        let now = Instant::now();
        let output = self.inner.output()?;
        // once the command has been executed we log it's success or failure.
        if log {
            if output.status.success() {
                info!(
                    "Completed in {}ms: {:?}",
                    now.elapsed().as_millis(),
                    &self.inner
                );
            } else {
                warn!(
                    "Failed in {}ms: {:?}",
                    now.elapsed().as_millis(),
                    &self.inner
                );
            }
        }
        if !output.status.success() {
            return Err(anyhow!("failed to run cargo command"));
        }
        Ok(output)
    }
}

#[derive(Debug, Default)]
pub struct CargoArgs {
    pub all_targets: bool,
}

/// Represents an invocations of cargo that will call multiple other invocations of
/// cargo based on groupings implied by the contents of <workspace-root>/x.toml.
pub enum CargoCommand<'a> {
    Bench(&'a CargoConfig, &'a [OsString], &'a [OsString]),
    Check(&'a CargoConfig),
    Clippy(&'a CargoConfig, &'a [OsString]),
    Fix(&'a CargoConfig, &'a [OsString]),
    Test {
        cargo_config: &'a CargoConfig,
        direct_args: &'a [OsString],
        args: &'a [OsString],
        env: &'a [(&'a str, &'a str)],
    },
}

impl<'a> CargoCommand<'a> {
    pub fn cargo_config(&self) -> &CargoConfig {
        match self {
            CargoCommand::Bench(config, _, _) => config,
            CargoCommand::Check(config) => config,
            CargoCommand::Clippy(config, _) => config,
            CargoCommand::Fix(config, _) => config,
            CargoCommand::Test { cargo_config, .. } => cargo_config,
        }
    }

    pub fn run_on_local_package(&self, args: &CargoArgs) -> Result<()> {
        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .args(self.direct_args())
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn run_on_packages<I, S>(&self, packages: I, args: &CargoArgs) -> Result<()>
    where
        I: IntoIterator<Item = S> + Clone,
        S: AsRef<OsStr>,
    {
        // Early return if we have no packages to run
        if packages.clone().into_iter().count() == 0 {
            return Ok(());
        }

        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .current_dir(project_root())
            .args(self.direct_args())
            .packages(packages)
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn run_on_all_packages(&self, args: &CargoArgs) -> Result<()> {
        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .current_dir(project_root())
            .workspace()
            .args(self.direct_args())
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn run_with_exclusions<I, S>(&self, exclusions: I, args: &CargoArgs) -> Result<()>
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .current_dir(project_root())
            .workspace()
            .args(self.direct_args())
            .exclusions(exclusions)
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn as_str(&self) -> &'static str {
        match self {
            CargoCommand::Bench(_, _, _) => "bench",
            CargoCommand::Check(_) => "check",
            CargoCommand::Clippy(_, _) => "clippy",
            CargoCommand::Fix(_, _) => "fix",
            CargoCommand::Test { .. } => "test",
        }
    }

    fn pass_through_args(&self) -> &[OsString] {
        match self {
            CargoCommand::Bench(_, _, args) => args,
            CargoCommand::Check(_) => &[],
            CargoCommand::Clippy(_, args) => args,
            CargoCommand::Fix(_, args) => args,
            CargoCommand::Test { args, .. } => args,
        }
    }

    fn direct_args(&self) -> &[OsString] {
        match self {
            CargoCommand::Bench(_, direct_args, _) => direct_args,
            CargoCommand::Check(_) => &[],
            CargoCommand::Clippy(_, _) => &[],
            CargoCommand::Fix(_, _) => &[],
            CargoCommand::Test { direct_args, .. } => direct_args,
        }
    }

    pub fn get_extra_env(&self) -> &[(&str, &str)] {
        match self {
            CargoCommand::Bench(_, _, _) => &[],
            CargoCommand::Check(_) => &[],
            CargoCommand::Clippy(_, _) => &[],
            CargoCommand::Fix(_, _) => &[],
            CargoCommand::Test { env, .. } => &env,
        }
    }

    fn apply_args(cargo: &mut Cargo, args: &CargoArgs) {
        if args.all_targets {
            cargo.all_targets();
        }
    }
}
<commit_msg>x: set CARGO envvar with the cargo binary being invoked<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{config::CargoConfig, utils::project_root, Result};
use anyhow::anyhow;
use log::{info, warn};
use std::{
    env,
    ffi::{OsStr, OsString},
    path::Path,
    process::{Command, Output, Stdio},
    time::Instant,
};

const RUST_TOOLCHAIN_VERSION: &str = include_str!("../../../rust-toolchain");
const RUSTUP_TOOLCHAIN: &str = "RUSTUP_TOOLCHAIN";
const CARGO: &str = "CARGO";

pub struct Cargo {
    inner: Command,
    pass_through_args: Vec<OsString>,
    env_additions: Vec<(OsString, OsString)>,
}

impl Cargo {
    pub fn new<S: AsRef<OsStr>>(cargo_config: &CargoConfig, command: S) -> Self {
        // run rustup to find correct toolchain
        let output = Command::new("rustup")
            .arg("which")
            .arg("--toolchain")
            .arg(&cargo_config.toolchain)
            .arg("cargo")
            .output()
            .expect("failed to execute rustup which");
        let (cargo_binary, cargo_flags) = if output.status.success() {
            (
                String::from_utf8(output.stdout)
                    .expect("error parsing rustup which output into utf8"),
                &cargo_config.flags,
            )
        } else {
            println!(
                "WARN: Rust toolchain {} not installed; falling back to legacy Cargo resolver.",
                cargo_config.toolchain,
            );
            println!(
                "WARN: Run `rustup toolchain install {}` to use the new resolver.",
                cargo_config.toolchain,
            );
            ("cargo".to_string(), &None)
        };

        println!(
            "cargo_binary = {}, cargo_flags = {:?}",
            cargo_binary, cargo_flags
        );

        let mut inner = Command::new(str::trim(&cargo_binary));
        if let Some(flags) = &cargo_flags {
            inner.arg(&flags);
        }

        // The environment is inherited for child processes so we only need to set RUSTUP_TOOLCHAIN
        // if it isn't already present in the environment
        if env::var_os(RUSTUP_TOOLCHAIN).is_none() {
            inner.env(RUSTUP_TOOLCHAIN, RUST_TOOLCHAIN_VERSION);
        }

        // Set the `CARGO` envvar with the path to the cargo binary being used
        inner.env(CARGO, cargo_binary.trim());

        inner.arg(command);
        Self {
            inner,
            pass_through_args: Vec::new(),
            env_additions: Vec::new(),
        }
    }

    pub fn all(&mut self) -> &mut Self {
        self.inner.arg("--all");
        self
    }

    pub fn workspace(&mut self) -> &mut Self {
        self.inner.arg("--workspace");
        self
    }

    pub fn all_targets(&mut self) -> &mut Self {
        self.inner.arg("--all-targets");
        self
    }

    pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Self {
        self.inner.current_dir(dir);
        self
    }

    pub fn packages<I, S>(&mut self, packages: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for p in packages {
            self.inner.arg("--package");
            self.inner.arg(p);
        }
        self
    }

    pub fn exclusions<I, S>(&mut self, exclusions: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for e in exclusions {
            self.inner.arg("--exclude");
            self.inner.arg(e);
        }
        self
    }

    /// Adds a series of arguments to x's target command.
    pub fn args<I, S>(&mut self, args: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        self.inner.args(args);
        self
    }

    /// Adds an argument to x's target command.
    #[allow(dead_code)]
    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
        self.inner.arg(arg);
        self
    }

    /// Adds "Pass Through" arguments to x's target command.
    /// Pass through arguments appear after a double dash " -- " and may
    /// not be handled/checked by x's target command itself, but an underlying executable.
    pub fn pass_through<I, S>(&mut self, args: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for a in args {
            self.pass_through_args.push(a.as_ref().to_owned());
        }
        self
    }

    /// Passes extra environment variables to x's target command.
    pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
    where
        I: IntoIterator<Item = (K, V)>,
        K: AsRef<OsStr>,
        V: AsRef<OsStr>,
    {
        for (key, val) in vars {
            self.env(key, val);
        }
        self
    }

    /// Passes an extra environment variable to x's target command.
    pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
    where
        K: AsRef<OsStr>,
        V: AsRef<OsStr>,
    {
        self.env_additions
            .push((key.as_ref().to_os_string(), val.as_ref().to_os_string()));
        self
    }

    pub fn run(&mut self) -> Result<()> {
        self.inner.stdout(Stdio::inherit()).stderr(Stdio::inherit());
        self.do_run(true).map(|_| ())
    }

    /// Runs this command, capturing the standard output into a `Vec<u8>`.
    /// No logging/timing will be displayed as the result of this call from x.
    pub fn run_with_output(&mut self) -> Result<Vec<u8>> {
        self.inner.stderr(Stdio::inherit());
        // Since system out hijacked don't log for this command
        self.do_run(false).map(|o| o.stdout)
    }

    /// Internal run command, where the magic happens.
    /// If log is true, any environment variable overrides will be logged, the full command will be logged,
    /// and after the command's output reaches stdout, the command will be printed again along with the time took
    /// to process the command (wallclock) in ms.
    fn do_run(&mut self, log: bool) -> Result<Output> {
        // these arguments are passed through cargo/x to underlying executable (test, clippy, etc)
        if !self.pass_through_args.is_empty() {
            self.inner.arg("--").args(&self.pass_through_args);
        }

        // once all the arguments are added to the command we can log it.
        if log {
            self.env_additions
                .iter()
                .for_each(|t| info!("Env {:?}: {:?}", t.0, t.1));
            info!("Executing: {:?}", &self.inner);
        }
        self.inner
            .envs(self.env_additions.iter().map(|(k, v)| (k, v)));
        let now = Instant::now();
        let output = self.inner.output()?;
        // once the command has been executed we log it's success or failure.
        if log {
            if output.status.success() {
                info!(
                    "Completed in {}ms: {:?}",
                    now.elapsed().as_millis(),
                    &self.inner
                );
            } else {
                warn!(
                    "Failed in {}ms: {:?}",
                    now.elapsed().as_millis(),
                    &self.inner
                );
            }
        }
        if !output.status.success() {
            return Err(anyhow!("failed to run cargo command"));
        }
        Ok(output)
    }
}

#[derive(Debug, Default)]
pub struct CargoArgs {
    pub all_targets: bool,
}

/// Represents an invocations of cargo that will call multiple other invocations of
/// cargo based on groupings implied by the contents of <workspace-root>/x.toml.
pub enum CargoCommand<'a> {
    Bench(&'a CargoConfig, &'a [OsString], &'a [OsString]),
    Check(&'a CargoConfig),
    Clippy(&'a CargoConfig, &'a [OsString]),
    Fix(&'a CargoConfig, &'a [OsString]),
    Test {
        cargo_config: &'a CargoConfig,
        direct_args: &'a [OsString],
        args: &'a [OsString],
        env: &'a [(&'a str, &'a str)],
    },
}

impl<'a> CargoCommand<'a> {
    pub fn cargo_config(&self) -> &CargoConfig {
        match self {
            CargoCommand::Bench(config, _, _) => config,
            CargoCommand::Check(config) => config,
            CargoCommand::Clippy(config, _) => config,
            CargoCommand::Fix(config, _) => config,
            CargoCommand::Test { cargo_config, .. } => cargo_config,
        }
    }

    pub fn run_on_local_package(&self, args: &CargoArgs) -> Result<()> {
        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .args(self.direct_args())
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn run_on_packages<I, S>(&self, packages: I, args: &CargoArgs) -> Result<()>
    where
        I: IntoIterator<Item = S> + Clone,
        S: AsRef<OsStr>,
    {
        // Early return if we have no packages to run
        if packages.clone().into_iter().count() == 0 {
            return Ok(());
        }

        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .current_dir(project_root())
            .args(self.direct_args())
            .packages(packages)
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn run_on_all_packages(&self, args: &CargoArgs) -> Result<()> {
        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .current_dir(project_root())
            .workspace()
            .args(self.direct_args())
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn run_with_exclusions<I, S>(&self, exclusions: I, args: &CargoArgs) -> Result<()>
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .current_dir(project_root())
            .workspace()
            .args(self.direct_args())
            .exclusions(exclusions)
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn as_str(&self) -> &'static str {
        match self {
            CargoCommand::Bench(_, _, _) => "bench",
            CargoCommand::Check(_) => "check",
            CargoCommand::Clippy(_, _) => "clippy",
            CargoCommand::Fix(_, _) => "fix",
            CargoCommand::Test { .. } => "test",
        }
    }

    fn pass_through_args(&self) -> &[OsString] {
        match self {
            CargoCommand::Bench(_, _, args) => args,
            CargoCommand::Check(_) => &[],
            CargoCommand::Clippy(_, args) => args,
            CargoCommand::Fix(_, args) => args,
            CargoCommand::Test { args, .. } => args,
        }
    }

    fn direct_args(&self) -> &[OsString] {
        match self {
            CargoCommand::Bench(_, direct_args, _) => direct_args,
            CargoCommand::Check(_) => &[],
            CargoCommand::Clippy(_, _) => &[],
            CargoCommand::Fix(_, _) => &[],
            CargoCommand::Test { direct_args, .. } => direct_args,
        }
    }

    pub fn get_extra_env(&self) -> &[(&str, &str)] {
        match self {
            CargoCommand::Bench(_, _, _) => &[],
            CargoCommand::Check(_) => &[],
            CargoCommand::Clippy(_, _) => &[],
            CargoCommand::Fix(_, _) => &[],
            CargoCommand::Test { env, .. } => &env,
        }
    }

    fn apply_args(cargo: &mut Cargo, args: &CargoArgs) {
        if args.all_targets {
            cargo.all_targets();
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::hash;
use std::marker::{MarkerTrait, PhantomData};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

use {Encode, EncodePtr, Message, ToMessage};
use runtime::Object;

#[link(name = "objc", kind = "dylib")]
extern {
    fn objc_retain(obj: *mut Object) -> *mut Object;
    fn objc_release(obj: *mut Object);
}

/// A type used to mark that a struct owns the object(s) it contains,
/// so it has the sole references to them.
pub enum Owned { }
/// A type used to mark that the object(s) a struct contains are shared,
/// so there may be other references to them.
pub enum Shared { }

/// A type that marks what type of ownership a struct has over the object(s)
/// it contains; specifically, either `Owned` or `Shared`.
pub trait Ownership : MarkerTrait { }
impl Ownership for Owned { }
impl Ownership for Shared { }

/// A pointer type for Objective-C's reference counted objects. The object of
/// an `Id` is retained and sent a `release` message when the `Id` is dropped.
///
/// An `Id` may be either `Owned` or `Shared`, represented by the types `Id`
/// and `ShareId`, respectively. If owned, there are no other references to the
/// object and the `Id` can be mutably dereferenced. `ShareId`, however, can
/// only be immutably dereferenced because there may be other references to the
/// object, but a `ShareId` can be cloned to provide more references to the
/// object. An owned `Id` can be "downgraded" freely to a `ShareId`, but there
/// is no way to safely upgrade back.
#[unsafe_no_drop_flag]
pub struct Id<T, O = Owned> where T: Message, O: Ownership {
    ptr: *mut T,
    own: PhantomData<O>,
}

impl<T, O> Id<T, O> where T: Message, O: Ownership {
    unsafe fn from_ptr_unchecked(ptr: *mut T) -> Id<T, O> {
        Id { ptr: ptr, own: PhantomData }
    }

    /// Constructs an `Id` from a pointer to an unretained object and
    /// retains it. Panics if the pointer is null.
    /// Unsafe because the pointer must be to a valid object and
    /// the caller must ensure the ownership is correct.
    pub unsafe fn from_ptr(ptr: *mut T) -> Id<T, O> {
        assert!(!ptr.is_null(), "Attempted to construct an Id from a null pointer");
        let ptr = objc_retain(ptr as *mut Object) as *mut T;
        Id::from_ptr_unchecked(ptr)
    }

    /// Constructs an `Id` from a pointer to a retained object; this won't
    /// retain the pointer, so the caller must ensure the object has a +1
    /// retain count. Panics if the pointer is null.
    /// Unsafe because the pointer must be to a valid object and
    /// the caller must ensure the ownership is correct.
    pub unsafe fn from_retained_ptr(ptr: *mut T) -> Id<T, O> {
        assert!(!ptr.is_null(), "Attempted to construct an Id from a null pointer");
        Id::from_ptr_unchecked(ptr)
    }
}

impl<T> Id<T, Owned> where T: Message {
    /// "Downgrade" an owned `Id` to a `ShareId`, allowing it to be cloned.
    pub fn share(self) -> ShareId<T> {
        unsafe {
            let ptr = self.ptr;
            mem::forget(self);
            Id::from_ptr_unchecked(ptr)
        }
    }
}

impl<T, O> Encode for Id<T, O> where T: Message + EncodePtr, O: Ownership {
    fn code() -> &'static str {
        <T as EncodePtr>::ptr_code()
    }
}

impl<T, O> ToMessage for Id<T, O> where T: Message, O: Ownership {
    fn as_id_ptr(&self) -> *mut Object {
        self.ptr as *mut Object
    }
}

impl<T> Clone for Id<T, Shared> where T: Message {
    fn clone(&self) -> ShareId<T> {
        unsafe {
            let ptr = objc_retain(self.ptr as *mut Object) as *mut T;
            Id::from_ptr_unchecked(ptr)
        }
    }
}

#[unsafe_destructor]
impl<T, O> Drop for Id<T, O> where T: Message, O: Ownership {
    fn drop(&mut self) {
        if !self.ptr.is_null() {
            let ptr = mem::replace(&mut self.ptr, ptr::null_mut());
            unsafe {
                objc_release(ptr as *mut Object);
            }
        }
    }
}

impl<T, O> Deref for Id<T, O> where T: Message, O: Ownership {
    type Target = T;

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

impl<T> DerefMut for Id<T, Owned> where T: Message {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.ptr }
    }
}

impl<T, O> PartialEq for Id<T, O> where T: Message + PartialEq, O: Ownership {
    fn eq(&self, other: &Id<T, O>) -> bool {
        self.deref() == other.deref()
    }

    fn ne(&self, other: &Id<T, O>) -> bool {
        self.deref() != other.deref()
    }
}

impl<T, O> Eq for Id<T, O> where T: Message + Eq, O: Ownership { }

impl<T, O> hash::Hash for Id<T, O> where T: Message + hash::Hash, O: Ownership {
    fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
        self.deref().hash(state)
    }
}

impl<T, O> fmt::Debug for Id<T, O> where T: Message + fmt::Debug, O: Ownership {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.deref().fmt(f)
    }
}

/// A convenient alias for a shared `Id`.
pub type ShareId<T> = Id<T, Shared>;

/// Extension methods for slices containing `Id`s.
pub trait IdSlice {
    type Item;

    /// Convert a slice of `Id`s into a slice of references
    fn as_refs_slice(&self) -> &[&Self::Item];
}

impl<T, O> IdSlice for [Id<T, O>] where T: Message, O: Ownership {
    type Item = T;

    fn as_refs_slice(&self) -> &[&T] {
        unsafe {
            mem::transmute(self)
        }
    }
}

#[cfg(test)]
mod tests {
    use runtime::Object;
    use test_utils;

    fn retain_count(obj: &Object) -> usize {
        unsafe { msg_send![obj, retainCount] }
    }

    #[test]
    fn test_clone() {
        let obj = test_utils::sample_object();
        assert!(retain_count(&obj) == 1);

        let obj = obj.share();
        assert!(retain_count(&obj) == 1);

        let cloned = obj.clone();
        assert!(retain_count(&cloned) == 2);
        assert!(retain_count(&obj) == 2);

        drop(obj);
        assert!(retain_count(&cloned) == 1);
    }
}
<commit_msg>Wrote retain/release wrapper functions.<commit_after>use std::fmt;
use std::hash;
use std::marker::{MarkerTrait, PhantomData};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

use {Encode, EncodePtr, Message, ToMessage};
use runtime::Object;

#[link(name = "objc", kind = "dylib")]
extern {
    fn objc_retain(obj: *mut Object) -> *mut Object;
    fn objc_release(obj: *mut Object);
}

unsafe fn retain<T: Message>(ptr: *mut T) -> *mut T {
    objc_retain(ptr as *mut Object) as *mut T
}

unsafe fn release<T: Message>(ptr: *mut T) {
    objc_release(ptr as *mut Object);
}

/// A type used to mark that a struct owns the object(s) it contains,
/// so it has the sole references to them.
pub enum Owned { }
/// A type used to mark that the object(s) a struct contains are shared,
/// so there may be other references to them.
pub enum Shared { }

/// A type that marks what type of ownership a struct has over the object(s)
/// it contains; specifically, either `Owned` or `Shared`.
pub trait Ownership : MarkerTrait { }
impl Ownership for Owned { }
impl Ownership for Shared { }

/// A pointer type for Objective-C's reference counted objects. The object of
/// an `Id` is retained and sent a `release` message when the `Id` is dropped.
///
/// An `Id` may be either `Owned` or `Shared`, represented by the types `Id`
/// and `ShareId`, respectively. If owned, there are no other references to the
/// object and the `Id` can be mutably dereferenced. `ShareId`, however, can
/// only be immutably dereferenced because there may be other references to the
/// object, but a `ShareId` can be cloned to provide more references to the
/// object. An owned `Id` can be "downgraded" freely to a `ShareId`, but there
/// is no way to safely upgrade back.
#[unsafe_no_drop_flag]
pub struct Id<T, O = Owned> where T: Message, O: Ownership {
    ptr: *mut T,
    own: PhantomData<O>,
}

impl<T, O> Id<T, O> where T: Message, O: Ownership {
    unsafe fn from_ptr_unchecked(ptr: *mut T) -> Id<T, O> {
        Id { ptr: ptr, own: PhantomData }
    }

    /// Constructs an `Id` from a pointer to an unretained object and
    /// retains it. Panics if the pointer is null.
    /// Unsafe because the pointer must be to a valid object and
    /// the caller must ensure the ownership is correct.
    pub unsafe fn from_ptr(ptr: *mut T) -> Id<T, O> {
        assert!(!ptr.is_null(), "Attempted to construct an Id from a null pointer");
        let ptr = retain(ptr);
        Id::from_ptr_unchecked(ptr)
    }

    /// Constructs an `Id` from a pointer to a retained object; this won't
    /// retain the pointer, so the caller must ensure the object has a +1
    /// retain count. Panics if the pointer is null.
    /// Unsafe because the pointer must be to a valid object and
    /// the caller must ensure the ownership is correct.
    pub unsafe fn from_retained_ptr(ptr: *mut T) -> Id<T, O> {
        assert!(!ptr.is_null(), "Attempted to construct an Id from a null pointer");
        Id::from_ptr_unchecked(ptr)
    }
}

impl<T> Id<T, Owned> where T: Message {
    /// "Downgrade" an owned `Id` to a `ShareId`, allowing it to be cloned.
    pub fn share(self) -> ShareId<T> {
        unsafe {
            let ptr = self.ptr;
            mem::forget(self);
            Id::from_ptr_unchecked(ptr)
        }
    }
}

impl<T, O> Encode for Id<T, O> where T: Message + EncodePtr, O: Ownership {
    fn code() -> &'static str {
        <T as EncodePtr>::ptr_code()
    }
}

impl<T, O> ToMessage for Id<T, O> where T: Message, O: Ownership {
    fn as_id_ptr(&self) -> *mut Object {
        self.ptr as *mut Object
    }
}

impl<T> Clone for Id<T, Shared> where T: Message {
    fn clone(&self) -> ShareId<T> {
        unsafe {
            let ptr = retain(self.ptr);
            Id::from_ptr_unchecked(ptr)
        }
    }
}

#[unsafe_destructor]
impl<T, O> Drop for Id<T, O> where T: Message, O: Ownership {
    fn drop(&mut self) {
        if !self.ptr.is_null() {
            let ptr = mem::replace(&mut self.ptr, ptr::null_mut());
            unsafe {
                release(ptr);
            }
        }
    }
}

impl<T, O> Deref for Id<T, O> where T: Message, O: Ownership {
    type Target = T;

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

impl<T> DerefMut for Id<T, Owned> where T: Message {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.ptr }
    }
}

impl<T, O> PartialEq for Id<T, O> where T: Message + PartialEq, O: Ownership {
    fn eq(&self, other: &Id<T, O>) -> bool {
        self.deref() == other.deref()
    }

    fn ne(&self, other: &Id<T, O>) -> bool {
        self.deref() != other.deref()
    }
}

impl<T, O> Eq for Id<T, O> where T: Message + Eq, O: Ownership { }

impl<T, O> hash::Hash for Id<T, O> where T: Message + hash::Hash, O: Ownership {
    fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
        self.deref().hash(state)
    }
}

impl<T, O> fmt::Debug for Id<T, O> where T: Message + fmt::Debug, O: Ownership {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.deref().fmt(f)
    }
}

/// A convenient alias for a shared `Id`.
pub type ShareId<T> = Id<T, Shared>;

/// Extension methods for slices containing `Id`s.
pub trait IdSlice {
    type Item;

    /// Convert a slice of `Id`s into a slice of references
    fn as_refs_slice(&self) -> &[&Self::Item];
}

impl<T, O> IdSlice for [Id<T, O>] where T: Message, O: Ownership {
    type Item = T;

    fn as_refs_slice(&self) -> &[&T] {
        unsafe {
            mem::transmute(self)
        }
    }
}

#[cfg(test)]
mod tests {
    use runtime::Object;
    use test_utils;

    fn retain_count(obj: &Object) -> usize {
        unsafe { msg_send![obj, retainCount] }
    }

    #[test]
    fn test_clone() {
        let obj = test_utils::sample_object();
        assert!(retain_count(&obj) == 1);

        let obj = obj.share();
        assert!(retain_count(&obj) == 1);

        let cloned = obj.clone();
        assert!(retain_count(&cloned) == 2);
        assert!(retain_count(&obj) == 2);

        drop(obj);
        assert!(retain_count(&cloned) == 1);
    }
}
<|endoftext|>


<commit_before>extern mod std;
extern mod pcre;

use pcre::*;

#[cfg(test)]
mod test_util {
    pub trait OptionUtil<T> {
        fn is_some_and(&self, blk: &fn(T) -> bool) -> bool;
        fn is_none_and(&self, blk: &fn() -> bool) -> bool;
    }

    impl<T: Copy> OptionUtil<T> for Option<T> {
        fn is_some_and(&self, blk: &fn(T) -> bool) -> bool {
            match *self {
                Some(t) => blk(t),
                None => false,
            }
        }

        // Who wants?
        fn is_none_and(&self, blk: &fn() -> bool) -> bool {
            match *self {
                Some(_) => false,
                None => blk(),
            }
        }
    }

    pub trait ResultUtil<T, U> {
        fn is_ok_and(&self, blk: &fn(T) -> bool) -> bool;
        fn is_err_and(&self, blk: &fn(U) -> bool) -> bool;
    }

    impl<T: Copy, U: Copy> ResultUtil<T, U> for Result<T, U> {
        fn is_ok_and(&self, blk: &fn(T) -> bool) -> bool {
            match *self {
                Ok(t) => blk(t),
                Err(_) => false,
            }
        }

        fn is_err_and(&self, blk: &fn(U) -> bool) -> bool {
            match *self {
                Ok(_) => false,
                Err(u) => blk(u),
            }
        }
    }

    #[test]
    fn test_option_util() {
        let s = Some(42);

        assert!( s.is_some());
        assert!( s.is_some_and(|i| i == 42));
        assert!(!s.is_some_and(|i| i != 42));

        assert!(!s.is_none());
        assert!(!s.is_none_and(|| true));
        assert!(!s.is_none_and(|| false));

        let n = None::<()>;

        assert!( n.is_none());
        assert!( n.is_none_and(|| true));
        assert!(!n.is_none_and(|| false));

        assert!(!n.is_some());
        assert!(!n.is_some_and(|_nil| true));
        assert!(!n.is_some_and(|_nil| false));

    }

    #[test]
    fn test_result_util() {
        let o: Result<int, ()> = Ok(42);

        assert!( o.is_ok());
        assert!( o.is_ok_and(|i| i == 42));
        assert!(!o.is_ok_and(|i| i != 42));

        assert!(!o.is_err());
        assert!(!o.is_err_and(|_nil| true));
        assert!(!o.is_err_and(|_nil| false));

        let e: Result<(), int> = Err(42);

        assert!( e.is_err());
        assert!( e.is_err_and(|i| i == 42));
        assert!(!e.is_err_and(|i| i != 42));

        assert!(!e.is_ok());
        assert!(!e.is_ok_and(|_nil| true));
        assert!(!e.is_ok_and(|_nil| false));
    }
}

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

    #[test]
    fn test_compile() {
        let r = compile("foo", 0);
        assert!(r.is_ok());

        let r = compile("foo(", 0);
        assert!(do r.is_err_and |e| {
            assert!(e.code == 14);
            assert!(e.reason == @~"missing )");
            assert!(e.offset == 4u);
            true
        });
    }

    #[test]
    fn test_search() {
        let r = search("(foo)bar", "foobar", 0);
        assert!(r.is_ok());

        let r = search(~"(foo)bar", "foobar", 0);
        assert!(r.is_ok());

        let r = search(@"(foo)bar", "foobar", 0);
        assert!(r.is_ok());

        let c = compile("(foo)bar", 0);
        let p = c.get();

        let r = search(p, "foobar", 0);
        assert!(r.is_ok());

        let r = search(c, "foobar", 0);
        assert!(r.is_ok());

        let r = search("foo(", "foobar", 0);
        match r {
            Err(CompileErr(e)) => {
                assert!(e.code == 14);
                assert!(e.reason == @~"missing )");
                assert!(e.offset == 4u);
            }
            _ => { fail!(); }
        }

        let r = search("(foo)bar", "baz", 0);
        assert!(is_nomatch(r));

        let r = search("はにほ", "いろはにほへと", 0);
        assert!(r.is_ok_and(|m| m.begin() == 6u && m.end() == 15u));

        let r = search("ちりぬ", "いろはにほへと", 0);
        assert!(is_nomatch(r));
    }

    // compile() accepts compile options (obviously)
    #[test]
    fn test_search_options_0() {
        let r = search(compile("foobar", PCRE_CASELESS), "FOOBAR", 0);
        assert!(r.is_ok());
    }

    // search() accepts compile options
    #[test]
    fn test_search_options_1() {
        let r = search("foobar", "FOOBAR", PCRE_CASELESS);
        assert!(r.is_ok());
    }

    // Inline options supersedes exec-time compile options
    #[test]
    fn test_search_options_2() {
        let r = search("(?-i)foobar", "FOOBAR", PCRE_CASELESS);
        assert!(r.is_err());
    }

    // Compile-time compile options supersedes exec-time compile options
    #[test]
    fn test_search_options_3() {
        let r = search(compile("foobar", 0), "FOOBAR", PCRE_CASELESS);
        assert!(r.is_err());
    }

    #[test]
    fn test_replace() {
        let r = replace("bcd", "AbcdbcdbcdE", "BCD", 0);
        assert!(r.is_ok_and(|s| s == @~"ABCDbcdbcdE"));
    }

    #[test]
    fn test_replace_from() {
        let r = replace_from("bcd", "AbcdbcdbcdE", "BCD", 2u, 0);
        assert!(r.is_ok_and(|s| s == @~"AbcdBCDbcdE"));
    }

    #[test]
    fn test_replace_fn() {
        let r = replace_fn("bcd", "AbcdbcdbcdE",
                           |m| { str::to_upper(m.matched()) }, 0);
        assert!(r.is_ok_and(|s| s == @~"ABCDbcdbcdE"));
    }

    #[test]
    fn test_replace_fn_from() {
        let r = replace_fn_from("bcd", "AbcdbcdbcdE",
                                |m| { str::to_upper(m.matched()) }, 2u, 0);
        assert!(r.is_ok_and(|s| s == @~"AbcdBCDbcdE"));
    }

    #[test]
    fn test_replace_all() {
        let r = replace_all("bcd", "AbcdbcdbcdE", "BCD", 0);
        assert!(r.is_ok_and(|s| s == @~"ABCDBCDBCDE"));
    }

    #[test]
    fn test_replace_all_from() {
        let r = replace_all_from("bcd", "AbcdbcdbcdE", "BCD", 2u, 0);
        assert!(r.is_ok_and(|s| s == @~"AbcdBCDBCDE"));
    }

    #[test]
    fn test_replace_all_fn() {
        let r = replace_all_fn("bcd", "AbcdbcdbcdE",
                                |m| { str::to_upper(m.matched()) }, 0);
        assert!(r.is_ok_and(|s| s == @~"ABCDBCDBCDE"));
    }

    #[test]
    fn test_replace_all_fn_from() {
        let r = replace_all_fn_from("bcd", "AbcdbcdbcdE",
                                    |m| { str::to_upper(m.matched()) }, 2u, 0);
        assert!(r.is_ok_and(|s| s == @~"AbcdBCDBCDE"));
    }
}

#[cfg(test)]
mod test_match_extensions {
    use test_util::*;
    use pcre::*;

    #[test]
    fn test_group() {
        let r = search("(foo)bar(baz)", "foobarbaz", 0);
        assert!(do r.is_ok_and |m| {
            assert!(m.group(0u).is_some_and(|s| s == @~"foobarbaz"));
            assert!(m.group(1u).is_some_and(|s| s == @~"foo"));
            assert!(m.group(2u).is_some_and(|s| s == @~"baz"));
            assert!(m.group(3u).is_none());
            true
        });
    }

    #[test]
    fn test_subgroups() {
        let r = search("(foo)bar(baz)", "foobarbaz", 0);
        assert!(do r.is_ok_and |m| {
            do vec::all2(m.subgroups(), ~[~"foo", ~"baz"]) |s, t| { s == t }
        });
    }

    #[test]
    fn test_group_count() {
        let r = search("foobarbaz", "foobarbaz", 0);
        assert!(r.is_ok_and(|m| m.group_count() == 0u));

        let r = search("(foo)bar(baz)", "foobarbaz", 0);
        assert!(r.is_ok_and(|m| m.group_count() == 2u));

        let r = search("(?:foo)bar", "foobar", 0);
        assert!(r.is_ok_and(|m| m.group_count() == 0u));

        let r = search("(?:(foo)|baz)bar", "foobar", 0);
        assert!(r.is_ok_and(|m| m.group_count() == 1u));

        let r = search("(?:foo|(baz))bar", "foobar", 0);
        assert!(r.is_ok_and(|m| m.group_count() == 1u));
    }

    #[test]
    fn test_unmatched_group() {
        let r = search("((foo)|bar)_(baz)", "bar_baz", 0);
        assert!(do r.is_ok_and |m| {
            assert!(m.group(1u).is_some_and(|s| s == @~"bar"));
            assert!(m.group(2u).is_none());
            assert!(m.group(3u).is_some_and(|s| s == @~"baz"));
            true
        });

        let r = search("(foo)?(bar)(baz)", "barbaz", 0);
        assert!(do r.is_ok_and |m| {
            assert!(m.group(1u).is_none());
            assert!(m.group(2u).is_some_and(|s| s == @~"bar"));
            assert!(m.group(3u).is_some_and(|s| s == @~"baz"));
            true
        });

        let r = search("(foo)?(?<bar_name>bar)", "bar", 0);
        assert!(do r.is_ok_and |m| {
            assert!(m.named_group("bar_name").is_some_and(|s| s == @~"bar"));
            true
        });
    }

    #[test]
    fn test_group_names() {
        let r = search("(?<foo_name>foo)bar", "foobar", 0);
        assert!(do r.is_ok_and |m| {
            do vec::all2(m.group_names(), ~[~"foo_name"]) |s, t| { s == t }
        });
    }

    #[test]
    fn test_named_group() {
        let r = search("(?<foo_name>f..)bar", "foobar", 0);
        assert!(do r.is_ok_and |m| {
            assert!(m.named_group("foo_name").is_some_and(|s| s == @~"foo"));
            assert!(m.named_group("nonexistent").is_none());
            true
        });
    }
}
<commit_msg>Fix imports<commit_after>extern mod std;
extern mod pcre;

#[cfg(test)]
mod test_util {
    pub trait OptionUtil<T> {
        fn is_some_and(&self, blk: &fn(T) -> bool) -> bool;
        fn is_none_and(&self, blk: &fn() -> bool) -> bool;
    }

    impl<T: Copy> OptionUtil<T> for Option<T> {
        fn is_some_and(&self, blk: &fn(T) -> bool) -> bool {
            match *self {
                Some(t) => blk(t),
                None => false,
            }
        }

        // Who wants?
        fn is_none_and(&self, blk: &fn() -> bool) -> bool {
            match *self {
                Some(_) => false,
                None => blk(),
            }
        }
    }

    pub trait ResultUtil<T, U> {
        fn is_ok_and(&self, blk: &fn(T) -> bool) -> bool;
        fn is_err_and(&self, blk: &fn(U) -> bool) -> bool;
    }

    impl<T: Copy, U: Copy> ResultUtil<T, U> for Result<T, U> {
        fn is_ok_and(&self, blk: &fn(T) -> bool) -> bool {
            match *self {
                Ok(t) => blk(t),
                Err(_) => false,
            }
        }

        fn is_err_and(&self, blk: &fn(U) -> bool) -> bool {
            match *self {
                Ok(_) => false,
                Err(u) => blk(u),
            }
        }
    }

    #[test]
    fn test_option_util() {
        let s = Some(42);

        assert!( s.is_some());
        assert!( s.is_some_and(|i| i == 42));
        assert!(!s.is_some_and(|i| i != 42));

        assert!(!s.is_none());
        assert!(!s.is_none_and(|| true));
        assert!(!s.is_none_and(|| false));

        let n = None::<()>;

        assert!( n.is_none());
        assert!( n.is_none_and(|| true));
        assert!(!n.is_none_and(|| false));

        assert!(!n.is_some());
        assert!(!n.is_some_and(|_nil| true));
        assert!(!n.is_some_and(|_nil| false));

    }

    #[test]
    fn test_result_util() {
        let o: Result<int, ()> = Ok(42);

        assert!( o.is_ok());
        assert!( o.is_ok_and(|i| i == 42));
        assert!(!o.is_ok_and(|i| i != 42));

        assert!(!o.is_err());
        assert!(!o.is_err_and(|_nil| true));
        assert!(!o.is_err_and(|_nil| false));

        let e: Result<(), int> = Err(42);

        assert!( e.is_err());
        assert!( e.is_err_and(|i| i == 42));
        assert!(!e.is_err_and(|i| i != 42));

        assert!(!e.is_ok());
        assert!(!e.is_ok_and(|_nil| true));
        assert!(!e.is_ok_and(|_nil| false));
    }
}

#[cfg(test)]
mod tests {
    use test_util::*;
    use pcre::pcre::*;
    use pcre::consts::*;

    #[test]
    fn test_compile() {
        let r = compile("foo", 0);
        assert!(r.is_ok());

        let r = compile("foo(", 0);
        assert!(do r.is_err_and |e| {
            assert!(e.code == 14);
            assert!(e.reason == @~"missing )");
            assert!(e.offset == 4u);
            true
        });
    }

    #[test]
    fn test_search() {
        let r = search("(foo)bar", "foobar", 0);
        assert!(r.is_ok());

        let r = search(~"(foo)bar", "foobar", 0);
        assert!(r.is_ok());

        let r = search(@"(foo)bar", "foobar", 0);
        assert!(r.is_ok());

        let c = compile("(foo)bar", 0);
        let p = c.get();

        let r = search(p, "foobar", 0);
        assert!(r.is_ok());

        let r = search(c, "foobar", 0);
        assert!(r.is_ok());

        let r = search("foo(", "foobar", 0);
        match r {
            Err(CompileErr(e)) => {
                assert!(e.code == 14);
                assert!(e.reason == @~"missing )");
                assert!(e.offset == 4u);
            }
            _ => { fail!(); }
        }

        let r = search("(foo)bar", "baz", 0);
        assert!(is_nomatch(r));

        let r = search("はにほ", "いろはにほへと", 0);
        assert!(r.is_ok_and(|m| m.begin() == 6u && m.end() == 15u));

        let r = search("ちりぬ", "いろはにほへと", 0);
        assert!(is_nomatch(r));
    }

    // compile() accepts compile options (obviously)
    #[test]
    fn test_search_options_0() {
        let r = search(compile("foobar", PCRE_CASELESS), "FOOBAR", 0);
        assert!(r.is_ok());
    }

    // search() accepts compile options
    #[test]
    fn test_search_options_1() {
        let r = search("foobar", "FOOBAR", PCRE_CASELESS);
        assert!(r.is_ok());
    }

    // Inline options supersedes exec-time compile options
    #[test]
    fn test_search_options_2() {
        let r = search("(?-i)foobar", "FOOBAR", PCRE_CASELESS);
        assert!(r.is_err());
    }

    // Compile-time compile options supersedes exec-time compile options
    #[test]
    fn test_search_options_3() {
        let r = search(compile("foobar", 0), "FOOBAR", PCRE_CASELESS);
        assert!(r.is_err());
    }

    #[test]
    fn test_replace() {
        let r = replace("bcd", "AbcdbcdbcdE", "BCD", 0);
        assert!(r.is_ok_and(|s| s == @~"ABCDbcdbcdE"));
    }

    #[test]
    fn test_replace_from() {
        let r = replace_from("bcd", "AbcdbcdbcdE", "BCD", 2u, 0);
        assert!(r.is_ok_and(|s| s == @~"AbcdBCDbcdE"));
    }

    #[test]
    fn test_replace_fn() {
        let r = replace_fn("bcd", "AbcdbcdbcdE",
                           |m| { str::to_upper(m.matched()) }, 0);
        assert!(r.is_ok_and(|s| s == @~"ABCDbcdbcdE"));
    }

    #[test]
    fn test_replace_fn_from() {
        let r = replace_fn_from("bcd", "AbcdbcdbcdE",
                                |m| { str::to_upper(m.matched()) }, 2u, 0);
        assert!(r.is_ok_and(|s| s == @~"AbcdBCDbcdE"));
    }

    #[test]
    fn test_replace_all() {
        let r = replace_all("bcd", "AbcdbcdbcdE", "BCD", 0);
        assert!(r.is_ok_and(|s| s == @~"ABCDBCDBCDE"));
    }

    #[test]
    fn test_replace_all_from() {
        let r = replace_all_from("bcd", "AbcdbcdbcdE", "BCD", 2u, 0);
        assert!(r.is_ok_and(|s| s == @~"AbcdBCDBCDE"));
    }

    #[test]
    fn test_replace_all_fn() {
        let r = replace_all_fn("bcd", "AbcdbcdbcdE",
                                |m| { str::to_upper(m.matched()) }, 0);
        assert!(r.is_ok_and(|s| s == @~"ABCDBCDBCDE"));
    }

    #[test]
    fn test_replace_all_fn_from() {
        let r = replace_all_fn_from("bcd", "AbcdbcdbcdE",
                                    |m| { str::to_upper(m.matched()) }, 2u, 0);
        assert!(r.is_ok_and(|s| s == @~"AbcdBCDBCDE"));
    }
}

#[cfg(test)]
mod test_match_extensions {
    use test_util::*;
    use pcre::pcre::*;

    #[test]
    fn test_group() {
        let r = search("(foo)bar(baz)", "foobarbaz", 0);
        assert!(do r.is_ok_and |m| {
            assert!(m.group(0u).is_some_and(|s| s == @~"foobarbaz"));
            assert!(m.group(1u).is_some_and(|s| s == @~"foo"));
            assert!(m.group(2u).is_some_and(|s| s == @~"baz"));
            assert!(m.group(3u).is_none());
            true
        });
    }

    #[test]
    fn test_subgroups() {
        let r = search("(foo)bar(baz)", "foobarbaz", 0);
        assert!(do r.is_ok_and |m| {
            do vec::all2(m.subgroups(), ~[~"foo", ~"baz"]) |s, t| { s == t }
        });
    }

    #[test]
    fn test_group_count() {
        let r = search("foobarbaz", "foobarbaz", 0);
        assert!(r.is_ok_and(|m| m.group_count() == 0u));

        let r = search("(foo)bar(baz)", "foobarbaz", 0);
        assert!(r.is_ok_and(|m| m.group_count() == 2u));

        let r = search("(?:foo)bar", "foobar", 0);
        assert!(r.is_ok_and(|m| m.group_count() == 0u));

        let r = search("(?:(foo)|baz)bar", "foobar", 0);
        assert!(r.is_ok_and(|m| m.group_count() == 1u));

        let r = search("(?:foo|(baz))bar", "foobar", 0);
        assert!(r.is_ok_and(|m| m.group_count() == 1u));
    }

    #[test]
    fn test_unmatched_group() {
        let r = search("((foo)|bar)_(baz)", "bar_baz", 0);
        assert!(do r.is_ok_and |m| {
            assert!(m.group(1u).is_some_and(|s| s == @~"bar"));
            assert!(m.group(2u).is_none());
            assert!(m.group(3u).is_some_and(|s| s == @~"baz"));
            true
        });

        let r = search("(foo)?(bar)(baz)", "barbaz", 0);
        assert!(do r.is_ok_and |m| {
            assert!(m.group(1u).is_none());
            assert!(m.group(2u).is_some_and(|s| s == @~"bar"));
            assert!(m.group(3u).is_some_and(|s| s == @~"baz"));
            true
        });

        let r = search("(foo)?(?<bar_name>bar)", "bar", 0);
        assert!(do r.is_ok_and |m| {
            assert!(m.named_group("bar_name").is_some_and(|s| s == @~"bar"));
            true
        });
    }

    #[test]
    fn test_group_names() {
        let r = search("(?<foo_name>foo)bar", "foobar", 0);
        assert!(do r.is_ok_and |m| {
            do vec::all2(m.group_names(), ~[~"foo_name"]) |s, t| { s == t }
        });
    }

    #[test]
    fn test_named_group() {
        let r = search("(?<foo_name>f..)bar", "foobar", 0);
        assert!(do r.is_ok_and |m| {
            assert!(m.named_group("foo_name").is_some_and(|s| s == @~"foo"));
            assert!(m.named_group("nonexistent").is_none());
            true
        });
    }
}
<|endoftext|>


<commit_before>pub use slist::List::{Cons,Nil};
use std::fmt;
use std::ops::Index;

/// Convenience macro for making lists.
///
/// # Example:
///
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::slist;
/// # use seax_svm::slist::List::{Cons, Nil};
/// # fn main () {
/// assert_eq!(
///     list!(1i32, 2i32, 3i32),
///     Cons(1i32, Box::new(Cons(2i32, Box::new(Cons(3i32, Box::new(Nil))))))
///     );
/// # }
/// ```
#[macro_export]
macro_rules! list(
    ( $e:expr, $($rest:expr),+ ) => ( Cons($e, Box::new(list!( $( $rest ),+ )) ));
    ( $e:expr ) => ( Cons($e, Box::new(Nil)) );
    () => ( Box::new(Nil) );
);

/// Common functions for an immutable Stack abstract data type.
pub trait Stack<T> {

    /// Push an item to the top of the stack, returning a new stack
    fn push(self, item : T) -> Self;

    /// Pop the top element of the stack. Returns an Option on a T and
    /// a new Stack<T> to replace this.
    fn pop(self)            -> Option<(T, Self)>;

    /// Peek at the top item of the stack.
    ///
    /// Returns Some<T> if there is an item on top of the stack,
    /// and None if the stack is empty.
    fn peek(&self)          -> Option<&T>;

    /// Returns an empty stack.
    fn empty()              -> Self;
}

/// Stack implementation using a cons list
impl<T> Stack<T> for List<T> {

    /// Push an item to the top of the stack, returning a new stack.
    ///
    /// # Examples:
    /// ```
    /// use seax_svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// assert_eq!(s.peek(), None);
    /// s = s.push(1);
    /// assert_eq!(s.peek(), Some(&1));
    /// s = s.push(6);
    /// assert_eq!(s.peek(), Some(&6));
    /// ```
    fn push(self, item: T) -> List<T> {
        Cons(item, box self)
    }

    /// Pop the top element of the stack.
    ///
    /// Pop the top element of the stack. Returns an
    /// `Option<(T,List<T>)>` containing the top element and a new
    /// `List<T>` with that item removed, or `None` if the stack is
    /// empty.
    ///
    /// # Examples:
    /// ```
    /// # use seax_svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// s = s.push(2);
    /// s = s.push(1);
    /// let pop_result = s.pop().unwrap();
    /// s = pop_result.1;
    /// assert_eq!(s.peek(), Some(&2));
    /// assert_eq!(pop_result.0, 1);
    /// ```
    fn pop(self) -> Option<(T,List<T>)> {
        match self {
            Cons(item, new_self)    => Some((item, *new_self)),
            Nil                     => None
        }
    }

    fn empty() -> List<T> {
        Nil
    }

    /// Peek at the top element of the stack.
    ///
    /// Peek at the top element of the stack. Returns an `Option<&T>`
    /// with a borrowed pointer to the top element, or `None` if the
    /// stack is empty.
    ///
    /// # Examples:
    /// ```
    /// # use seax_svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// s = s.push(2);
    /// s = s.push(1);
    /// let pop_result = s.pop().unwrap();
    /// s = pop_result.1;
    /// assert_eq!(s.peek(), Some(&2));
    /// assert_eq!(pop_result.0, 1);
    /// ```
    fn peek(&self) -> Option<&T> {
        match self {
            &Nil => None,
            &Cons(ref it,_) => Some(it)
        }
    }

}

/// Singly-linked cons list.
///
/// This is used internally to represent list primitives in the
/// machine.
#[derive(PartialEq,Clone,Debug)]
pub enum List<T> {
    /// Cons cell containing a `T` and a link to the tail
    Cons(T, Box<List<T>>),
    /// The empty list.
    Nil,
}

/// Public implementation for List.
impl<T> List<T> {

    /// Creates a new empty list
    pub fn new() -> List<T> {
        Nil
    }

    /// Prepends the given item to the list.
    ///
    /// Returns the list containing the new  head item.
    /// This is an O(1) operation.
    pub fn prepend(self, it: T) -> List<T> {
        Cons(it, box self)
    }

    /// Appends an item to the end of the list.
    ///
    /// This is an O(n) operation.
    pub fn append(self, it: T) {
        unimplemented!()
    }

    /// Returns the length of the list.
    pub fn length (&self) -> usize {
        match *self {
            Cons(_, ref tail) => 1 + tail.length(),
            Nil => 0
        }
    }

    /// Provide a forward iterator
    #[inline]
    pub fn iter<'a>(&'a self) -> ListIterator<'a, T> {
        ListIterator{current: self}
    }

    pub fn last(&self) -> &T {
        match *self {
            Cons(ref car, box Nil) => &car,
            Cons(_, ref cdr @ box Cons(_,_)) => cdr.last(),
            Nil => panic!("Last called on empty list")
        }
    }
}

impl<'a, T> fmt::Display for List<T> where T: fmt::Display{

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: replace toString with this
        match *self {
            Cons(ref head, ref tail) => write!(f, "({}, {})", head, tail),
            Nil => write!(f,"nil")
        }
    }
}

/// Wraps a List<T> to allow it to be used as an Iterator<T>
pub struct ListIterator<'a, T:'a> {
    current: &'a List<T>
}

/// Implementation of Iterator for List. This allows iteration by
/// link hopping.
impl<'a, T> Iterator for ListIterator<'a, T> {
    type Item = &'a T;

    /// Get the next element from the list.
    ///
    /// Get the next element from the list. Returns a `Some<T>`, or `Nil`
    /// if at the end of the list.
    ///
    /// # Examples:
    /// ```
    /// # #[macro_use] extern crate seax_svm;
    /// # use seax_svm::slist;
    /// # use seax_svm::slist::List;
    /// # use seax_svm::slist::List::{Cons, Nil};
    /// # fn main () {
    /// let list = list!(1,2,3);
    /// let mut iter = list.iter();
    /// assert_eq!(iter.next().unwrap(), &1);
    /// assert_eq!(iter.next().unwrap(), &2);
    /// assert_eq!(iter.next().unwrap(), &3);
    /// # }
    /// ```
    /// ```
    /// # #[macro_use] extern crate seax_svm;
    /// # use seax_svm::slist;
    /// # use seax_svm::slist::List;
    /// # use seax_svm::slist::List::{Cons, Nil};
    /// # fn main () {
    /// let l: List<isize> = list!(1,2,3,4,5,6);
    /// let mut string = String::new();
    /// for item in l.iter() {
    ///     string.push_str((item.to_string() + ", ").as_slice());
    /// }
    /// assert_eq!(string.as_slice(), "1, 2, 3, 4, 5, 6, ")
    /// # }
    /// ```
    fn next(&mut self) -> Option<&'a T> {
        match self.current {
            &Cons(ref head, box ref tail) => { self.current = tail; Some(head) },
            &Nil => None
        }
    }
}

impl<'a, T> ExactSizeIterator for ListIterator<'a, T> {
    fn len(&self) -> usize {
        self.current.length()
    }
}
/// Implementation of indexing for `List<T>`.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::slist;
/// # use seax_svm::slist::List;
/// # use seax_svm::slist::List::{Cons, Nil};
/// # fn main () {
/// let list = list!(1,2,3,4,5,6);
/// assert_eq!(list[0us], 1);
/// # }
/// ```
impl<T> Index<usize> for List<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: &usize) -> &'a T {
        match *_index {
            0usize => match *self {
                Cons(ref car, _) => car,
                Nil => panic!("List index {} out of range", _index)
            },
            1usize => match *self {
                Cons(_, box Cons(ref cdr, _)) => cdr,
                Cons(_, box Nil) => panic!("List index {} out of range", _index),
                Nil => panic!("List index {} out of range", _index)
            },
            i if i == self.length() => self.last(),
            i if i > self.length()  => panic!("List index {:?} out of range.", _index),
            i if i > 1usize => {
                let mut it = self.iter();
                for _ in 0usize .. i{
                    it.next();
                }
                it.next().unwrap()
            },
            _ => panic!("Expected an index i such that i >= 0, got {:?}.", _index)
        }
    }
}
/// Implementation of indexing for `List<T>`.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::slist;
/// # use seax_svm::slist::List;
/// # use seax_svm::slist::List::{Cons, Nil};
/// # fn main () {
/// let list = list!(1,2,3,4,5,6);
/// assert_eq!(list[0is], 1);
/// # }
/// ```
impl<T> Index<isize> for List<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: &isize) -> &'a T {
        match *_index {
            0isize => match *self {
                Cons(ref car, _) => car,
                Nil => panic!("List index {} out of range", _index)
            },
            1isize => match *self {
                Cons(_, box Cons(ref cdr, _)) => cdr,
                Cons(_, box Nil) => panic!("List index {} out of range", _index),
                Nil => panic!("List index {} out of range", _index)
            },
            i if i == self.length() as isize => self.last(),
            i if i > self.length() as isize => panic!("List index {:?} out of range.", _index),
            i if i > 1isize => {
                let mut it = self.iter();
                for _ in 0isize .. i{
                    it.next();
                }
                it.next().unwrap()
            },
            _ => panic!("Expected an index i such that i >= 0, got {:?}.", _index)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{List, Stack};
    use super::List::{Cons,Nil};

    #[test]
    fn test_list_length() {
        let full_list: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_list: List<i32> = List::new();
        assert_eq!(full_list.length(), 3);
        assert_eq!(empty_list.length(), 0);
    }

    #[test]
    fn test_list_to_string() {
        let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
        assert_eq!(l.to_string(), "(1, (2, (3, nil)))");
    }

    #[test]
    fn test_stack_length() {
        let full_stack: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_stack: List<i32> = Stack::empty();
        assert_eq!(full_stack.length(), 3);
        assert_eq!(empty_stack.length(), 0);
    }

    #[test]
    fn test_stack_peek() {
        let full_stack: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_stack: List<i32> = Stack::empty();
        assert_eq!(full_stack.peek(), Some(&1));
        assert_eq!(empty_stack.peek(), None);
    }

    #[test]
    fn test_stack_push() {
        let mut s: List<i32> = Stack::empty();
        assert_eq!(s.peek(), None);
        s = s.push(1);
        assert_eq!(s.peek(), Some(&1));
        s = s.push(6);
        assert_eq!(s.peek(), Some(&6));
    }

    #[test]
    fn test_stack_pop() {
        let mut s: List<i32> = Stack::empty();
        assert_eq!(s.peek(), None);
        s = s.push(1);
        assert_eq!(s.peek(), Some(&1));
        s = s.push(6);
        assert_eq!(s.peek(), Some(&6));
        let pop_result = s.pop().unwrap(); // should not break
        s = pop_result.1;
        assert_eq!(s.peek(), Some(&1));
        assert_eq!(pop_result.0, 6);
    }

    #[test]
    fn test_list_usize_indexing() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        assert_eq!(l[0usize],1);
        assert_eq!(l[1usize],2);
        assert_eq!(l[2usize],3);
        assert_eq!(l[3usize],4);
        assert_eq!(l[4usize],5);
        assert_eq!(l[5usize],6);
    }

    #[test]
    fn test_list_isize_indexing() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        assert_eq!(l[0isize],1);
        assert_eq!(l[1isize],2);
        assert_eq!(l[2isize],3);
        assert_eq!(l[3isize],4);
        assert_eq!(l[4isize],5);
        assert_eq!(l[5isize],6);
    }

    #[test]
    fn test_list_macro() {
        let l: List<i32> = list!(1i32, 2i32, 3i32);
        assert_eq!(l.to_string(), "(1, (2, (3, nil)))")
    }

    #[test]
    fn test_list_iter() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        let mut string = String::new();
        for item in l.iter() {
            string.push_str((item.to_string() + ", ").as_slice());
        }
        assert_eq!(string.as_slice(), "1, 2, 3, 4, 5, 6, ")
    }

}
<commit_msg>Update Index for List to use newest nightly behavior<commit_after>pub use slist::List::{Cons,Nil};
use std::fmt;
use std::ops::Index;

/// Convenience macro for making lists.
///
/// # Example:
///
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::slist;
/// # use seax_svm::slist::List::{Cons, Nil};
/// # fn main () {
/// assert_eq!(
///     list!(1i32, 2i32, 3i32),
///     Cons(1i32, Box::new(Cons(2i32, Box::new(Cons(3i32, Box::new(Nil))))))
///     );
/// # }
/// ```
#[macro_export]
macro_rules! list(
    ( $e:expr, $($rest:expr),+ ) => ( Cons($e, Box::new(list!( $( $rest ),+ )) ));
    ( $e:expr ) => ( Cons($e, Box::new(Nil)) );
    () => ( Box::new(Nil) );
);

/// Common functions for an immutable Stack abstract data type.
pub trait Stack<T> {

    /// Push an item to the top of the stack, returning a new stack
    fn push(self, item : T) -> Self;

    /// Pop the top element of the stack. Returns an Option on a T and
    /// a new Stack<T> to replace this.
    fn pop(self)            -> Option<(T, Self)>;

    /// Peek at the top item of the stack.
    ///
    /// Returns Some<T> if there is an item on top of the stack,
    /// and None if the stack is empty.
    fn peek(&self)          -> Option<&T>;

    /// Returns an empty stack.
    fn empty()              -> Self;
}

/// Stack implementation using a cons list
impl<T> Stack<T> for List<T> {

    /// Push an item to the top of the stack, returning a new stack.
    ///
    /// # Examples:
    /// ```
    /// use seax_svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// assert_eq!(s.peek(), None);
    /// s = s.push(1);
    /// assert_eq!(s.peek(), Some(&1));
    /// s = s.push(6);
    /// assert_eq!(s.peek(), Some(&6));
    /// ```
    fn push(self, item: T) -> List<T> {
        Cons(item, box self)
    }

    /// Pop the top element of the stack.
    ///
    /// Pop the top element of the stack. Returns an
    /// `Option<(T,List<T>)>` containing the top element and a new
    /// `List<T>` with that item removed, or `None` if the stack is
    /// empty.
    ///
    /// # Examples:
    /// ```
    /// # use seax_svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// s = s.push(2);
    /// s = s.push(1);
    /// let pop_result = s.pop().unwrap();
    /// s = pop_result.1;
    /// assert_eq!(s.peek(), Some(&2));
    /// assert_eq!(pop_result.0, 1);
    /// ```
    fn pop(self) -> Option<(T,List<T>)> {
        match self {
            Cons(item, new_self)    => Some((item, *new_self)),
            Nil                     => None
        }
    }

    fn empty() -> List<T> {
        Nil
    }

    /// Peek at the top element of the stack.
    ///
    /// Peek at the top element of the stack. Returns an `Option<&T>`
    /// with a borrowed pointer to the top element, or `None` if the
    /// stack is empty.
    ///
    /// # Examples:
    /// ```
    /// # use seax_svm::slist::{List,Stack};
    ///
    /// let mut s: List<isize> = Stack::empty();
    /// s = s.push(2);
    /// s = s.push(1);
    /// let pop_result = s.pop().unwrap();
    /// s = pop_result.1;
    /// assert_eq!(s.peek(), Some(&2));
    /// assert_eq!(pop_result.0, 1);
    /// ```
    fn peek(&self) -> Option<&T> {
        match self {
            &Nil => None,
            &Cons(ref it,_) => Some(it)
        }
    }

}

/// Singly-linked cons list.
///
/// This is used internally to represent list primitives in the
/// machine.
#[derive(PartialEq,Clone,Debug)]
pub enum List<T> {
    /// Cons cell containing a `T` and a link to the tail
    Cons(T, Box<List<T>>),
    /// The empty list.
    Nil,
}

/// Public implementation for List.
impl<T> List<T> {

    /// Creates a new empty list
    pub fn new() -> List<T> {
        Nil
    }

    /// Prepends the given item to the list.
    ///
    /// Returns the list containing the new  head item.
    /// This is an O(1) operation.
    pub fn prepend(self, it: T) -> List<T> {
        Cons(it, box self)
    }

    /// Appends an item to the end of the list.
    ///
    /// This is an O(n) operation.
    pub fn append(self, it: T) {
        unimplemented!()
    }

    /// Returns the length of the list.
    pub fn length (&self) -> usize {
        match *self {
            Cons(_, ref tail) => 1 + tail.length(),
            Nil => 0
        }
    }

    /// Provide a forward iterator
    #[inline]
    pub fn iter<'a>(&'a self) -> ListIterator<'a, T> {
        ListIterator{current: self}
    }

    pub fn last(&self) -> &T {
        match *self {
            Cons(ref car, box Nil) => &car,
            Cons(_, ref cdr @ box Cons(_,_)) => cdr.last(),
            Nil => panic!("Last called on empty list")
        }
    }
}

impl<'a, T> fmt::Display for List<T> where T: fmt::Display{

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: replace toString with this
        match *self {
            Cons(ref head, ref tail) => write!(f, "({}, {})", head, tail),
            Nil => write!(f,"nil")
        }
    }
}

/// Wraps a List<T> to allow it to be used as an Iterator<T>
pub struct ListIterator<'a, T:'a> {
    current: &'a List<T>
}

/// Implementation of Iterator for List. This allows iteration by
/// link hopping.
impl<'a, T> Iterator for ListIterator<'a, T> {
    type Item = &'a T;

    /// Get the next element from the list.
    ///
    /// Get the next element from the list. Returns a `Some<T>`, or `Nil`
    /// if at the end of the list.
    ///
    /// # Examples:
    /// ```
    /// # #[macro_use] extern crate seax_svm;
    /// # use seax_svm::slist;
    /// # use seax_svm::slist::List;
    /// # use seax_svm::slist::List::{Cons, Nil};
    /// # fn main () {
    /// let list = list!(1,2,3);
    /// let mut iter = list.iter();
    /// assert_eq!(iter.next().unwrap(), &1);
    /// assert_eq!(iter.next().unwrap(), &2);
    /// assert_eq!(iter.next().unwrap(), &3);
    /// # }
    /// ```
    /// ```
    /// # #[macro_use] extern crate seax_svm;
    /// # use seax_svm::slist;
    /// # use seax_svm::slist::List;
    /// # use seax_svm::slist::List::{Cons, Nil};
    /// # fn main () {
    /// let l: List<isize> = list!(1,2,3,4,5,6);
    /// let mut string = String::new();
    /// for item in l.iter() {
    ///     string.push_str((item.to_string() + ", ").as_slice());
    /// }
    /// assert_eq!(string.as_slice(), "1, 2, 3, 4, 5, 6, ")
    /// # }
    /// ```
    fn next(&mut self) -> Option<&'a T> {
        match self.current {
            &Cons(ref head, box ref tail) => { self.current = tail; Some(head) },
            &Nil => None
        }
    }
}

impl<'a, T> ExactSizeIterator for ListIterator<'a, T> {
    fn len(&self) -> usize {
        self.current.length()
    }
}
/// Implementation of indexing for `List<T>`.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::slist;
/// # use seax_svm::slist::List;
/// # use seax_svm::slist::List::{Cons, Nil};
/// # fn main () {
/// let list = list!(1,2,3,4,5,6);
/// assert_eq!(list[0us], 1);
/// # }
/// ```
impl<T> Index<usize> for List<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: usize) -> &'a T {
        match _index {
            0usize => match *self {
                Cons(ref car, _) => car,
                Nil => panic!("List index {} out of range", _index)
            },
            1usize => match *self {
                Cons(_, box Cons(ref cdr, _)) => cdr,
                Cons(_, box Nil) => panic!("List index {} out of range", _index),
                Nil => panic!("List index {} out of range", _index)
            },
            i if i == self.length() => self.last(),
            i if i > self.length()  => panic!("List index {:?} out of range.", _index),
            i if i > 1usize => {
                let mut it = self.iter();
                for _ in 0usize .. i{
                    it.next();
                }
                it.next().unwrap()
            },
            _ => panic!("Expected an index i such that i >= 0, got {:?}.", _index)
        }
    }
}
/// Implementation of indexing for `List<T>`.
///
/// # Examples:
/// ```
/// # #[macro_use] extern crate seax_svm;
/// # use seax_svm::slist;
/// # use seax_svm::slist::List;
/// # use seax_svm::slist::List::{Cons, Nil};
/// # fn main () {
/// let list = list!(1,2,3,4,5,6);
/// assert_eq!(list[0is], 1);
/// # }
/// ```
impl<T> Index<isize> for List<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: isize) -> &'a T {
        match _index {
            0isize => match *self {
                Cons(ref car, _) => car,
                Nil => panic!("List index {} out of range", _index)
            },
            1isize => match *self {
                Cons(_, box Cons(ref cdr, _)) => cdr,
                Cons(_, box Nil) => panic!("List index {} out of range", _index),
                Nil => panic!("List index {} out of range", _index)
            },
            i if i == self.length() as isize => self.last(),
            i if i > self.length() as isize => panic!("List index {:?} out of range.", _index),
            i if i > 1isize => {
                let mut it = self.iter();
                for _ in 0isize .. i{
                    it.next();
                }
                it.next().unwrap()
            },
            _ => panic!("Expected an index i such that i >= 0, got {:?}.", _index)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{List, Stack};
    use super::List::{Cons,Nil};

    #[test]
    fn test_list_length() {
        let full_list: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_list: List<i32> = List::new();
        assert_eq!(full_list.length(), 3);
        assert_eq!(empty_list.length(), 0);
    }

    #[test]
    fn test_list_to_string() {
        let l: List<i32> = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
        assert_eq!(l.to_string(), "(1, (2, (3, nil)))");
    }

    #[test]
    fn test_stack_length() {
        let full_stack: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_stack: List<i32> = Stack::empty();
        assert_eq!(full_stack.length(), 3);
        assert_eq!(empty_stack.length(), 0);
    }

    #[test]
    fn test_stack_peek() {
        let full_stack: List<i32> = list!(1i32, 2i32, 3i32);
        let empty_stack: List<i32> = Stack::empty();
        assert_eq!(full_stack.peek(), Some(&1));
        assert_eq!(empty_stack.peek(), None);
    }

    #[test]
    fn test_stack_push() {
        let mut s: List<i32> = Stack::empty();
        assert_eq!(s.peek(), None);
        s = s.push(1);
        assert_eq!(s.peek(), Some(&1));
        s = s.push(6);
        assert_eq!(s.peek(), Some(&6));
    }

    #[test]
    fn test_stack_pop() {
        let mut s: List<i32> = Stack::empty();
        assert_eq!(s.peek(), None);
        s = s.push(1);
        assert_eq!(s.peek(), Some(&1));
        s = s.push(6);
        assert_eq!(s.peek(), Some(&6));
        let pop_result = s.pop().unwrap(); // should not break
        s = pop_result.1;
        assert_eq!(s.peek(), Some(&1));
        assert_eq!(pop_result.0, 6);
    }

    #[test]
    fn test_list_usize_indexing() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        assert_eq!(l[0usize],1);
        assert_eq!(l[1usize],2);
        assert_eq!(l[2usize],3);
        assert_eq!(l[3usize],4);
        assert_eq!(l[4usize],5);
        assert_eq!(l[5usize],6);
    }

    #[test]
    fn test_list_isize_indexing() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        assert_eq!(l[0isize],1);
        assert_eq!(l[1isize],2);
        assert_eq!(l[2isize],3);
        assert_eq!(l[3isize],4);
        assert_eq!(l[4isize],5);
        assert_eq!(l[5isize],6);
    }

    #[test]
    fn test_list_macro() {
        let l: List<i32> = list!(1i32, 2i32, 3i32);
        assert_eq!(l.to_string(), "(1, (2, (3, nil)))")
    }

    #[test]
    fn test_list_iter() {
        let l: List<isize> = list!(1,2,3,4,5,6);
        let mut string = String::new();
        for item in l.iter() {
            string.push_str((item.to_string() + ", ").as_slice());
        }
        assert_eq!(string.as_slice(), "1, 2, 3, 4, 5, 6, ")
    }

}
<|endoftext|>