<commit_before>use crate::cli::Command;
use crate::util;
use anyhow::Result;
use std::collections::HashMap;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use structopt::StructOpt;

/// Get configuration options for a command or all commands
pub fn get(command: &str) -> Result<String> {
    let lines = read()?;

    if command == "all" {
        return Ok(lines.join("\n"));
    }

    for line in lines {
        if line.starts_with(command) {
            return Ok(line.strip_prefix(command).unwrap().trim().to_string());
        }
    }

    Ok("".to_string())
}

/// Set configuration options for a command
pub fn set(command: &str, args: &[String]) -> Result<()> {
    let mut lines = read()?;

    let mut found = false;
    for (index, line) in lines.iter().enumerate() {
        if line.starts_with(command) {
            // Merge existing and new args
            let config = line.strip_prefix(command).unwrap().trim().to_string();
            let merged = merge(command, &config, &args)?;
            lines[index] = format!("{} {}", command, merged.join(" "));
            found = true;
            break;
        }
    }

    if !found {
        // If not found, still call merge to ensure args are checked
        // and in a consistent format
        let merged = merge(command, "", &args)?;
        let line = format!("{} {}", command, merged.join(" "));
        lines.push(line)
    }

    write(lines)
}

/// Clear configuration options for a command or all commands
pub fn clear(command: &str) -> Result<()> {
    if command == "all" {
        write(vec![])
    } else {
        let mut lines = read()?;
        for (index, line) in lines.iter().enumerate() {
            if line.starts_with(command) {
                lines.remove(index);
                break;
            }
        }
        write(lines)
    }
}

/// Merge args into an existing configuration
pub fn merge(command: &str, config: &str, args: &[String]) -> Result<Vec<String>> {
    // Get a `clap::App` for the command that will be used to
    // validate the args being set and merge values with existing one
    let app = crate::cli::Args::clap();

    // Extract message from a `clap` error (excludes usage etc)
    fn arg_error_message(error: &structopt::clap::Error) -> String {
        let start = match error.message.find("error: ") {
            Some(found) => found + 7,
            None => 0,
        };
        let end = error
            .message
            .find("\n\n")
            .unwrap_or_else(|| error.message.len());
        error.message.as_str()[start..end].to_string()
    }

    // Check that the existing config is valid. If it is not, ignore it with warning.
    let config_matches = match app.clone().get_matches_from_safe(
        format!("stencila {} {}", command, config)
            .trim()
            .split_whitespace(),
    ) {
        Ok(matches) => matches,
        Err(error) => {
            tracing::warn!(
                "Existing config for {} is invalid and will be ignored: {}. Use `stencila config clear {}` or edit {}.",
                command, arg_error_message(&error), command, path()?.to_string_lossy()
            );
            structopt::clap::ArgMatches::new()
        }
    };

    // Parse the args, this will exit the process if there are errors or --help was used.
    let args_matches =
        app.get_matches_from([&["stencila".to_string(), command.to_string()], args].concat());

    // Do merge
    let mut args_map = HashMap::<&str, String>::new();
    if let Some(config) = config_matches.subcommand {
        for (name, arg) in config.matches.args {
            let value = if arg.vals.is_empty() {
                "".to_string()
            } else {
                format!("={}", arg.vals[0].to_str().unwrap_or_default())
            };
            args_map.insert(name, value.to_string());
        }
    }
    if let Some(args) = args_matches.subcommand {
        for (name, arg) in args.matches.args {
            let value = if arg.vals.is_empty() {
                "".to_string()
            } else {
                format!("={}", arg.vals[0].to_str().unwrap_or_default())
            };
            args_map.insert(name, value.to_string());
        }
    }

    // Create new vector or ags, sorted for determinism
    let mut args_vec: Vec<String> = args_map
        .iter()
        .map(|(name, value)| format!("--{}{}", name, value))
        .collect();
    args_vec.sort();

    Ok(args_vec)
}

/// Get the path of the configuration file
fn path() -> Result<PathBuf> {
    #[cfg(not(test))]
    return Ok(util::dirs::config(true)?.join("cli.txt"));

    // When running tests, avoid messing with users existing config
    #[cfg(test)]
    return Ok(std::env::temp_dir()
        .join("stencila")
        .join("test")
        .join("cli.txt"));
}

/// Read lines from the configuration file
fn read() -> Result<Vec<String>> {
    let config_file = path()?;
    let lines = fs::read_to_string(config_file)
        .unwrap_or_else(|_| "".to_string())
        .lines()
        .map(|line| line.to_string())
        .collect();
    Ok(lines)
}

/// Write lines to the configuration file
fn write(lines: Vec<String>) -> Result<()> {
    let config_file = path()?;
    let mut file = fs::File::create(config_file)?;
    file.write_all(lines.join("\n").as_bytes())?;
    file.sync_all()?;
    Ok(())
}

/// CLI options for the `config` command
#[cfg(feature = "cli")]
pub mod cli {
    use super::*;
    use structopt::StructOpt;
    use strum::VariantNames;

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Manage configuration options",
        setting = structopt::clap::AppSettings::DeriveDisplayOrder
    )]
    pub struct Args {
        #[structopt(subcommand)]
        pub action: Action,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::DeriveDisplayOrder
    )]
    pub enum Action {
        Get(Get),
        Set(Set),
        Clear(Clear),

        #[structopt(about = "Get the directories used for config, cache etc")]
        Dirs,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(about = "Get configuration options for a command")]
    pub struct Get {
        /// The command to get the config for. Use 'all' to get config for all commands.
        #[structopt(possible_values = [Command::VARIANTS, &["all"]].concat().as_slice())]
        pub command: String,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Set configuration options for a command",
        setting = structopt::clap::AppSettings::TrailingVarArg,
        setting = structopt::clap::AppSettings::AllowLeadingHyphen
    )]
    pub struct Set {
        /// The command to set the config for.
        #[structopt(possible_values = &Command::VARIANTS)]
        pub command: String,

        /// The options and flags to set for the command
        #[structopt(multiple = true)]
        pub args: Vec<String>,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(about = "Clear configuration options for a command")]
    pub struct Clear {
        /// The command to clear the config for. Use 'all' to clear the config for all commands.
        #[structopt(possible_values = [Command::VARIANTS, &["all"]].concat().as_slice())]
        pub command: String,
    }

    pub fn config(args: Args) -> Result<()> {
        let Args { action } = args;
        match action {
            Action::Get(action) => {
                let Get { command } = action;
                let config = super::get(&command)?;
                println!("{}", config)
            }
            Action::Set(action) => {
                let Set { command, args } = action;
                super::set(&command, &args)?;
            }
            Action::Clear(action) => {
                let Clear { command } = action;
                super::clear(&command)?;
            }
            Action::Dirs => {
                let config = util::dirs::config(false)?.display().to_string();
                let plugins = util::dirs::plugins(false)?.display().to_string();
                println!("config: {}\nplugins: {}", config, plugins);
            }
        };
        Ok(())
    }
}

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

    #[test]
    fn test_path() -> Result<()> {
        let path = path()?;
        assert!(path.starts_with(std::env::temp_dir()));
        Ok(())
    }

    #[test]
    fn test_merge() -> Result<()> {
        assert_eq!(merge("serve", "", &[])?, Vec::<String>::new());

        assert_eq!(
            merge("serve", "", &["--key=bar".to_string()])?,
            vec!["--key=bar".to_string()]
        );

        assert_eq!(
            merge("serve", "--key=bar", &["--key=baz".to_string()])?,
            vec!["--key=baz".to_string()]
        );

        assert_eq!(
            // Bad existing config just gets ignored
            merge("serve", "--bad", &[])?,
            Vec::<String>::new()
        );

        //merge("serve", "", &["--bad".to_string()]);

        Ok(())
    }

    #[test]
    fn test_set_get_clear() -> Result<()> {
        // This is a single test because otherwise there can
        // be conflicting writes to the test config file if
        // tests are run in parallel.

        clear("all")?;
        assert_eq!(get("all")?, "");

        set("serve", &vec!["--key=foo".to_string()])?;
        assert_eq!(get("serve")?, "--key=foo");

        set("serve", &vec!["--insecure".to_string()])?;
        assert_eq!(get("serve")?, "--insecure --key=foo");

        set("serve", &vec!["--key=bar".to_string()])?;
        assert_eq!(get("serve")?, "--insecure --key=bar");

        clear("serve")?;
        assert_eq!(get("serve")?, "");

        cli::config(cli::Args {
            action: cli::Action::Get(cli::Get {
                command: "serve".to_string(),
            }),
        })?;

        cli::config(cli::Args {
            action: cli::Action::Set(cli::Set {
                command: "serve".to_string(),
                args: vec![],
            }),
        })?;

        cli::config(cli::Args {
            action: cli::Action::Clear(cli::Clear {
                command: "serve".to_string(),
            }),
        })?;

        cli::config(cli::Args {
            action: cli::Action::Dirs,
        })
    }
}
<commit_msg>test(Config): Ensure dir for config file is present<commit_after>use crate::cli::Command;
use crate::util;
use anyhow::Result;
use std::collections::HashMap;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use structopt::StructOpt;

/// Get configuration options for a command or all commands
pub fn get(command: &str) -> Result<String> {
    let lines = read()?;

    if command == "all" {
        return Ok(lines.join("\n"));
    }

    for line in lines {
        if line.starts_with(command) {
            return Ok(line.strip_prefix(command).unwrap().trim().to_string());
        }
    }

    Ok("".to_string())
}

/// Set configuration options for a command
pub fn set(command: &str, args: &[String]) -> Result<()> {
    let mut lines = read()?;

    let mut found = false;
    for (index, line) in lines.iter().enumerate() {
        if line.starts_with(command) {
            // Merge existing and new args
            let config = line.strip_prefix(command).unwrap().trim().to_string();
            let merged = merge(command, &config, &args)?;
            lines[index] = format!("{} {}", command, merged.join(" "));
            found = true;
            break;
        }
    }

    if !found {
        // If not found, still call merge to ensure args are checked
        // and in a consistent format
        let merged = merge(command, "", &args)?;
        let line = format!("{} {}", command, merged.join(" "));
        lines.push(line)
    }

    write(lines)
}

/// Clear configuration options for a command or all commands
pub fn clear(command: &str) -> Result<()> {
    if command == "all" {
        write(vec![])
    } else {
        let mut lines = read()?;
        for (index, line) in lines.iter().enumerate() {
            if line.starts_with(command) {
                lines.remove(index);
                break;
            }
        }
        write(lines)
    }
}

/// Merge args into an existing configuration
pub fn merge(command: &str, config: &str, args: &[String]) -> Result<Vec<String>> {
    // Get a `clap::App` for the command that will be used to
    // validate the args being set and merge values with existing one
    let app = crate::cli::Args::clap();

    // Extract message from a `clap` error (excludes usage etc)
    fn arg_error_message(error: &structopt::clap::Error) -> String {
        let start = match error.message.find("error: ") {
            Some(found) => found + 7,
            None => 0,
        };
        let end = error
            .message
            .find("\n\n")
            .unwrap_or_else(|| error.message.len());
        error.message.as_str()[start..end].to_string()
    }

    // Check that the existing config is valid. If it is not, ignore it with warning.
    let config_matches = match app.clone().get_matches_from_safe(
        format!("stencila {} {}", command, config)
            .trim()
            .split_whitespace(),
    ) {
        Ok(matches) => matches,
        Err(error) => {
            tracing::warn!(
                "Existing config for {} is invalid and will be ignored: {}. Use `stencila config clear {}` or edit {}.",
                command, arg_error_message(&error), command, path()?.to_string_lossy()
            );
            structopt::clap::ArgMatches::new()
        }
    };

    // Parse the args, this will exit the process if there are errors or --help was used.
    let args_matches =
        app.get_matches_from([&["stencila".to_string(), command.to_string()], args].concat());

    // Do merge
    let mut args_map = HashMap::<&str, String>::new();
    if let Some(config) = config_matches.subcommand {
        for (name, arg) in config.matches.args {
            let value = if arg.vals.is_empty() {
                "".to_string()
            } else {
                format!("={}", arg.vals[0].to_str().unwrap_or_default())
            };
            args_map.insert(name, value.to_string());
        }
    }
    if let Some(args) = args_matches.subcommand {
        for (name, arg) in args.matches.args {
            let value = if arg.vals.is_empty() {
                "".to_string()
            } else {
                format!("={}", arg.vals[0].to_str().unwrap_or_default())
            };
            args_map.insert(name, value.to_string());
        }
    }

    // Create new vector or ags, sorted for determinism
    let mut args_vec: Vec<String> = args_map
        .iter()
        .map(|(name, value)| format!("--{}{}", name, value))
        .collect();
    args_vec.sort();

    Ok(args_vec)
}

/// Get the path of the configuration file
fn path() -> Result<PathBuf> {
    #[cfg(not(test))]
    return Ok(util::dirs::config(true)?.join("cli.txt"));

    // When running tests, avoid messing with users existing config
    #[cfg(test)]
    {
        let path = std::env::temp_dir()
            .join("stencila")
            .join("test")
            .join("cli.txt");
        fs::create_dir_all(path.parent().unwrap())?;
        return Ok(path);
    }
}

/// Read lines from the configuration file
fn read() -> Result<Vec<String>> {
    let config_file = path()?;
    let lines = fs::read_to_string(config_file)
        .unwrap_or_else(|_| "".to_string())
        .lines()
        .map(|line| line.to_string())
        .collect();
    Ok(lines)
}

/// Write lines to the configuration file
fn write(lines: Vec<String>) -> Result<()> {
    let config_file = path()?;
    let mut file = fs::File::create(config_file)?;
    file.write_all(lines.join("\n").as_bytes())?;
    file.sync_all()?;
    Ok(())
}

/// CLI options for the `config` command
#[cfg(feature = "cli")]
pub mod cli {
    use super::*;
    use structopt::StructOpt;
    use strum::VariantNames;

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Manage configuration options",
        setting = structopt::clap::AppSettings::DeriveDisplayOrder
    )]
    pub struct Args {
        #[structopt(subcommand)]
        pub action: Action,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::DeriveDisplayOrder
    )]
    pub enum Action {
        Get(Get),
        Set(Set),
        Clear(Clear),

        #[structopt(about = "Get the directories used for config, cache etc")]
        Dirs,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(about = "Get configuration options for a command")]
    pub struct Get {
        /// The command to get the config for. Use 'all' to get config for all commands.
        #[structopt(possible_values = [Command::VARIANTS, &["all"]].concat().as_slice())]
        pub command: String,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Set configuration options for a command",
        setting = structopt::clap::AppSettings::TrailingVarArg,
        setting = structopt::clap::AppSettings::AllowLeadingHyphen
    )]
    pub struct Set {
        /// The command to set the config for.
        #[structopt(possible_values = &Command::VARIANTS)]
        pub command: String,

        /// The options and flags to set for the command
        #[structopt(multiple = true)]
        pub args: Vec<String>,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(about = "Clear configuration options for a command")]
    pub struct Clear {
        /// The command to clear the config for. Use 'all' to clear the config for all commands.
        #[structopt(possible_values = [Command::VARIANTS, &["all"]].concat().as_slice())]
        pub command: String,
    }

    pub fn config(args: Args) -> Result<()> {
        let Args { action } = args;
        match action {
            Action::Get(action) => {
                let Get { command } = action;
                let config = super::get(&command)?;
                println!("{}", config)
            }
            Action::Set(action) => {
                let Set { command, args } = action;
                super::set(&command, &args)?;
            }
            Action::Clear(action) => {
                let Clear { command } = action;
                super::clear(&command)?;
            }
            Action::Dirs => {
                let config = util::dirs::config(false)?.display().to_string();
                let plugins = util::dirs::plugins(false)?.display().to_string();
                println!("config: {}\nplugins: {}", config, plugins);
            }
        };
        Ok(())
    }
}

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

    #[test]
    fn test_path() -> Result<()> {
        let path = path()?;
        assert!(path.starts_with(std::env::temp_dir()));
        Ok(())
    }

    #[test]
    fn test_merge() -> Result<()> {
        assert_eq!(merge("serve", "", &[])?, Vec::<String>::new());

        assert_eq!(
            merge("serve", "", &["--key=bar".to_string()])?,
            vec!["--key=bar".to_string()]
        );

        assert_eq!(
            merge("serve", "--key=bar", &["--key=baz".to_string()])?,
            vec!["--key=baz".to_string()]
        );

        assert_eq!(
            // Bad existing config just gets ignored
            merge("serve", "--bad", &[])?,
            Vec::<String>::new()
        );

        //merge("serve", "", &["--bad".to_string()]);

        Ok(())
    }

    #[test]
    fn test_set_get_clear() -> Result<()> {
        // This is a single test because otherwise there can
        // be conflicting writes to the test config file if
        // tests are run in parallel.

        clear("all")?;
        assert_eq!(get("all")?, "");

        set("serve", &vec!["--key=foo".to_string()])?;
        assert_eq!(get("serve")?, "--key=foo");

        set("serve", &vec!["--insecure".to_string()])?;
        assert_eq!(get("serve")?, "--insecure --key=foo");

        set("serve", &vec!["--key=bar".to_string()])?;
        assert_eq!(get("serve")?, "--insecure --key=bar");

        clear("serve")?;
        assert_eq!(get("serve")?, "");

        cli::config(cli::Args {
            action: cli::Action::Get(cli::Get {
                command: "serve".to_string(),
            }),
        })?;

        cli::config(cli::Args {
            action: cli::Action::Set(cli::Set {
                command: "serve".to_string(),
                args: vec![],
            }),
        })?;

        cli::config(cli::Args {
            action: cli::Action::Clear(cli::Clear {
                command: "serve".to_string(),
            }),
        })?;

        cli::config(cli::Args {
            action: cli::Action::Dirs,
        })
    }
}
<|endoftext|>


<commit_before>extern crate cairo;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Segment {
    Degenerate {            // A single lone point
        x: f64,
        y: f64
    },

    LineOrCurve {
        x1: f64, y1: f64,
        x2: f64, y2: f64,
        x3: f64, y3: f64,
        x4: f64, y4: f64
    },
}

enum SegmentState {
    Start,
    End
}

/* This converts a cairo_path_t into a list of curveto-like segments.  Each segment can be:
 *
 * 1. Segment::Degenerate => the segment is actually a single point (x, y)
 *
 * 2. Segment::LineOrCurve => either a lineto or a curveto (or the effective lineto that results from a closepath).
 *    We have the following points:
 *       P1 = (x1, y1)
 *       P2 = (x2, y2)
 *       P3 = (x3, y3)
 *       P4 = (x4, y4)
 *
 *    The start and end points are P1 and P4, respectively.
 *    The tangent at the start point is given by the vector (P2 - P1).
 *    The tangent at the end point is given by the vector (P4 - P3).
 *    The tangents also work if the segment refers to a lineto (they will both just point in the same direction).
 */

const EPSILON: f64 = 1e-10;

fn double_equals (a: f64, b: f64) -> bool {
    (a - b).abs () < EPSILON
}

fn make_degenerate (x: f64, y: f64) -> Segment {
    Segment::Degenerate { x: x, y: y}
}

fn make_curve (x1: f64, y1: f64,
               mut x2: f64, mut y2: f64,
               mut x3: f64, mut y3: f64,
               x4: f64, y4: f64) -> Segment {
    /* Fix the tangents for when the middle control points coincide with their respective endpoints */

    if double_equals (x2, x1) && double_equals (y2, y1) {
        x2 = x3;
        y2 = y3;
    }

    if double_equals (x3, x4) && double_equals (y3, y4) {
        x3 = x2;
        y3 = y2;
    }

    Segment::LineOrCurve {
        x1: x1, y1: y1,
        x2: x2, y2: y2,
        x3: x3, y3: y3,
        x4: x4, y4: y4
    }
}

fn make_line (x1: f64, y1: f64, x2: f64, y2: f64) -> Segment {
    make_curve (x1, y1, x2, y2, x1, y1, x2, y2)
}

pub fn path_to_segments (path: cairo::Path) -> Vec<Segment> {
    let mut last_x: f64;
    let mut last_y: f64;
    let mut cur_x: f64;
    let mut cur_y: f64;
    let mut subpath_start_x: f64;
    let mut subpath_start_y: f64;
    let mut segments: Vec<Segment>;
    let mut state: SegmentState;

    cur_x = 0.0;
    cur_y = 0.0;
    subpath_start_x = 0.0;
    subpath_start_y = 0.0;

    segments = Vec::new ();
    state = SegmentState::End;

    for cairo_segment in path.iter () {
        last_x = cur_x;
        last_y = cur_y;

        let needs_new_segment: bool;
        let seg: Segment;

        match cairo_segment {
            cairo::PathSegment::MoveTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = make_degenerate (cur_x, cur_y);
                needs_new_segment = true;

                subpath_start_x = cur_x;
                subpath_start_y = cur_y;

                state = SegmentState::Start;
            },

            cairo::PathSegment::LineTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = make_line (last_x, last_y, cur_x, cur_y);

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            },

            cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)) => {
                cur_x = x4;
                cur_y = y4;

                seg = make_curve (last_x, last_y, x2, y2, x3, y3, cur_x, cur_y);

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            }

            cairo::PathSegment::ClosePath => {
                cur_x = subpath_start_x;
                cur_y = subpath_start_y;

                seg = make_line (last_x, last_y, cur_x, cur_y);

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = false;
                        /* nothing; closepath after moveto (or a single lone closepath) does nothing */
                    }
                }
            }
        }

        if needs_new_segment {
            segments.push (seg);
        } else {
            let len = segments.len ();
            segments[len - 1] = seg;
        }
    }

    segments
}

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

    fn create_cr () -> cairo::Context {
        let surf = cairo::ImageSurface::create (cairo::Format::Rgb24, 1, 1);
        let cr = cairo::Context::new (&surf);

        cr
    }

    fn degenerate (x: f64, y: f64) -> Segment {
        Segment::Degenerate { x: x, y: y }
    }

    fn curve (x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) -> Segment {
        Segment::LineOrCurve {
            x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3, x4: x4, y4: y4
        }
    }

    fn line (x1: f64, y1: f64, x2: f64, y2: f64) -> Segment {
        curve (x1, y1, x2, y2, x1, y1, x2, y2)
    }

    fn test_path_to_segments (path: cairo::Path, expected_segments: Vec<Segment>) {
        let segments = path_to_segments (path);
        assert_eq! (expected_segments, segments);
    }

    /* Single open path */

    fn setup_open_path () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_open_path () {
        let expected_segments: Vec<Segment> = vec![
            line (10.0, 10.0, 20.0, 10.0),
            line (20.0, 10.0, 20.0, 20.0)
        ];

        test_path_to_segments (setup_open_path(), expected_segments);
    }

    /* Multiple open subpaths */

    fn setup_multiple_open_subpaths () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        cr.move_to (30.0, 30.0);
        cr.line_to (40.0, 30.0);
        cr.curve_to (50.0, 35.0, 60.0, 60.0, 70.0, 70.0);
        cr.line_to (80.0, 90.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_multiple_open_subpaths () {
        let expected_segments: Vec<Segment> = vec![
            line  (10.0, 10.0, 20.0, 10.0),
            line  (20.0, 10.0, 20.0, 20.0),

            line  (30.0, 30.0, 40.0, 30.0),
            curve (40.0, 30.0, 50.0, 35.0, 60.0, 60.0, 70.0, 70.0),
            line  (70.0, 70.0, 80.0, 90.0)
        ];

        test_path_to_segments (setup_multiple_open_subpaths (), expected_segments);
    }
}
<commit_msg>marker.rs: Test for a closed subpath.  We found a bug!<commit_after>extern crate cairo;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Segment {
    Degenerate {            // A single lone point
        x: f64,
        y: f64
    },

    LineOrCurve {
        x1: f64, y1: f64,
        x2: f64, y2: f64,
        x3: f64, y3: f64,
        x4: f64, y4: f64
    },
}

enum SegmentState {
    Start,
    End
}

/* This converts a cairo_path_t into a list of curveto-like segments.  Each segment can be:
 *
 * 1. Segment::Degenerate => the segment is actually a single point (x, y)
 *
 * 2. Segment::LineOrCurve => either a lineto or a curveto (or the effective lineto that results from a closepath).
 *    We have the following points:
 *       P1 = (x1, y1)
 *       P2 = (x2, y2)
 *       P3 = (x3, y3)
 *       P4 = (x4, y4)
 *
 *    The start and end points are P1 and P4, respectively.
 *    The tangent at the start point is given by the vector (P2 - P1).
 *    The tangent at the end point is given by the vector (P4 - P3).
 *    The tangents also work if the segment refers to a lineto (they will both just point in the same direction).
 */

const EPSILON: f64 = 1e-10;

fn double_equals (a: f64, b: f64) -> bool {
    (a - b).abs () < EPSILON
}

fn make_degenerate (x: f64, y: f64) -> Segment {
    Segment::Degenerate { x: x, y: y}
}

fn make_curve (x1: f64, y1: f64,
               mut x2: f64, mut y2: f64,
               mut x3: f64, mut y3: f64,
               x4: f64, y4: f64) -> Segment {
    /* Fix the tangents for when the middle control points coincide with their respective endpoints */

    if double_equals (x2, x1) && double_equals (y2, y1) {
        x2 = x3;
        y2 = y3;
    }

    if double_equals (x3, x4) && double_equals (y3, y4) {
        x3 = x2;
        y3 = y2;
    }

    Segment::LineOrCurve {
        x1: x1, y1: y1,
        x2: x2, y2: y2,
        x3: x3, y3: y3,
        x4: x4, y4: y4
    }
}

fn make_line (x1: f64, y1: f64, x2: f64, y2: f64) -> Segment {
    make_curve (x1, y1, x2, y2, x1, y1, x2, y2)
}

pub fn path_to_segments (path: cairo::Path) -> Vec<Segment> {
    let mut last_x: f64;
    let mut last_y: f64;
    let mut cur_x: f64;
    let mut cur_y: f64;
    let mut subpath_start_x: f64;
    let mut subpath_start_y: f64;
    let mut segments: Vec<Segment>;
    let mut state: SegmentState;

    cur_x = 0.0;
    cur_y = 0.0;
    subpath_start_x = 0.0;
    subpath_start_y = 0.0;

    segments = Vec::new ();
    state = SegmentState::End;

    for cairo_segment in path.iter () {
        last_x = cur_x;
        last_y = cur_y;

        let needs_new_segment: bool;
        let seg: Segment;

        match cairo_segment {
            cairo::PathSegment::MoveTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = make_degenerate (cur_x, cur_y);
                needs_new_segment = true;

                subpath_start_x = cur_x;
                subpath_start_y = cur_y;

                state = SegmentState::Start;
            },

            cairo::PathSegment::LineTo ((x, y)) => {
                cur_x = x;
                cur_y = y;

                seg = make_line (last_x, last_y, cur_x, cur_y);

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            },

            cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)) => {
                cur_x = x4;
                cur_y = y4;

                seg = make_curve (last_x, last_y, x2, y2, x3, y3, cur_x, cur_y);

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = true;
                    }
                }
            }

            cairo::PathSegment::ClosePath => {
                cur_x = subpath_start_x;
                cur_y = subpath_start_y;

                seg = make_line (last_x, last_y, cur_x, cur_y);

                match state {
                    SegmentState::Start => {
                        state = SegmentState::End;
                        needs_new_segment = false;
                    },

                    SegmentState::End => {
                        needs_new_segment = false;
                        /* nothing; closepath after moveto (or a single lone closepath) does nothing */
                    }
                }
            }
        }

        if needs_new_segment {
            segments.push (seg);
        } else {
            let len = segments.len ();
            segments[len - 1] = seg;
        }
    }

    segments
}

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

    fn create_cr () -> cairo::Context {
        let surf = cairo::ImageSurface::create (cairo::Format::Rgb24, 1, 1);
        let cr = cairo::Context::new (&surf);

        cr
    }

    fn degenerate (x: f64, y: f64) -> Segment {
        Segment::Degenerate { x: x, y: y }
    }

    fn curve (x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) -> Segment {
        Segment::LineOrCurve {
            x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3, x4: x4, y4: y4
        }
    }

    fn line (x1: f64, y1: f64, x2: f64, y2: f64) -> Segment {
        curve (x1, y1, x2, y2, x1, y1, x2, y2)
    }

    fn test_path_to_segments (path: cairo::Path, expected_segments: Vec<Segment>) {
        let segments = path_to_segments (path);
        assert_eq! (expected_segments, segments);
    }

    /* Single open path */

    fn setup_open_path () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_open_path () {
        let expected_segments: Vec<Segment> = vec![
            line (10.0, 10.0, 20.0, 10.0),
            line (20.0, 10.0, 20.0, 20.0)
        ];

        test_path_to_segments (setup_open_path(), expected_segments);
    }

    /* Multiple open subpaths */

    fn setup_multiple_open_subpaths () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);

        cr.move_to (30.0, 30.0);
        cr.line_to (40.0, 30.0);
        cr.curve_to (50.0, 35.0, 60.0, 60.0, 70.0, 70.0);
        cr.line_to (80.0, 90.0);

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_multiple_open_subpaths () {
        let expected_segments: Vec<Segment> = vec![
            line  (10.0, 10.0, 20.0, 10.0),
            line  (20.0, 10.0, 20.0, 20.0),

            line  (30.0, 30.0, 40.0, 30.0),
            curve (40.0, 30.0, 50.0, 35.0, 60.0, 60.0, 70.0, 70.0),
            line  (70.0, 70.0, 80.0, 90.0)
        ];

        test_path_to_segments (setup_multiple_open_subpaths (), expected_segments);
    }

    fn setup_closed_subpath () -> cairo::Path {
        let cr = create_cr ();

        cr.move_to (10.0, 10.0);
        cr.line_to (20.0, 10.0);
        cr.line_to (20.0, 20.0);
        cr.close_path ();

        let path = cr.copy_path ();
        path
    }

    #[test]
    fn path_to_segments_handles_closed_subpath () {
        let expected_segments: Vec<Segment> = vec![
            line (10.0, 10.0, 20.0, 10.0),
            line (20.0, 10.0, 20.0, 20.0),
            line (20.0, 20.0, 10.0, 10.0)
        ];

        test_path_to_segments (setup_closed_subpath (), expected_segments);
    }
}
<|endoftext|>


<commit_before>#![ allow( dead_code ) ]
#![ allow( unused_variables ) ]
#![ allow( non_camel_case_types ) ]

use regex::Regex;

pub fn regexp_is( src : &str ) -> bool
{
  let regexp = Regex::new(r"^\\/.*\\/[dgimsuUx]").unwrap();
  regexp.is_match( src )
}

//

pub struct split<'a>
{
  pub src : String,
  pub delimeter : Vec<&'a str>,
  pub preserving_empty : bool,
  pub preserving_delimeters : bool,
  pub preserving_quoting : bool,
  pub inlining_quoting : bool,
  pub stripping : bool,
  pub quoting : bool,
  pub quoting_prefixes : Vec<&'a str>,
  pub quoting_postfixes : Vec<&'a str>,
  pub on_delimeter : Option<fn( &'a str, usize, &'a str ) -> &'a str>,
  pub on_quote : Option<fn( &'a str, usize, &'a str ) -> &'a str>,
  formed : u8,
}

fn on_delimeter( src : &str ) -> &str
{
    src
}

impl Default for split<'_>
{
  fn default() -> Self
  {
    let opts = Self
    {
      src : String::from( "" ),
      delimeter : vec![ " " ],
      preserving_empty : true,
      preserving_delimeters : true,
      preserving_quoting : true,
      inlining_quoting : true,
      stripping : true,
      quoting : true,
      quoting_prefixes : vec![ "\"" ],
      quoting_postfixes : vec![ "\"" ],
      on_delimeter : None,
      on_quote : None,
      formed : 0,
    };
    return opts;
  }
}

//

#[derive(Debug, Clone)]
pub struct split_fast<'a>
{
  pub src : String,
  pub delimeter : Vec<&'a str>,
  pub preserving_empty : bool,
  pub preserving_delimeters : bool,
  formed : u8,
}

impl <'a>Default for split_fast<'a>
{
  fn default() -> Self
  {
    let opts = Self
    {
      src : String::from( "" ),
      delimeter : vec![ " " ],
      preserving_empty : true,
      preserving_delimeters : true,
      formed : 0,
    };
    opts
  }
}

impl<'a> split_fast<'a>
{
  pub fn src( &mut self, src : String ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.src = src;
    self
  }

  //

  pub fn delimeter( &mut self, delimeter : Vec<&'a str> ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.delimeter = delimeter;
    self
  }

  //

  pub fn preserving_empty( &mut self, preserving_empty : bool ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.preserving_empty = preserving_empty;
    self
  }

  //

  pub fn preserving_delimeters( &mut self, preserving_delimeters : bool ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.preserving_delimeters = preserving_delimeters;
    self
  }

  //

  pub fn form( self ) -> Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    Self { formed : 1, .. self }
  }
}

//

pub fn split_fast<'a>( o : &'a split_fast ) -> Vec<&'a str>
{
  let mut result: Vec<&str> = vec![];

  let delimeters = &o.delimeter;

  let preserving_empty = o.preserving_empty;
  let preserving_delimeters = o.preserving_delimeters;

  let mut found_delimeters = delimeters.clone();

  if !preserving_delimeters && delimeters.len() == 1
  {
    result = o.src.split( delimeters[ 0 ] ).collect();
    if !preserving_empty
    {
      result = result.iter().filter( | x | x.len() != 0 ).map( | x | *x ).collect::<Vec<_>>();
    }
  }
  else
  {
    let src_len = o.src.len();
    let delimeter_len = delimeters.len();
    if delimeter_len == 0
    {
      result.push( &*o.src );
      return result;
    }

    let mut closests : Vec<usize> = vec![];
    let mut position : usize = 0;
    let mut closest_position : usize = 0;
    let mut closest_index : i32 = -1;
    let mut has_empty_delimeter : bool = false;

    for d in 0..delimeter_len
    {
      let delimeter = delimeters[ d ];
      if regexp_is( delimeter )
      {
        unimplemented!( "regexp splitting is not implemented" );
      }
      else
      {
        if delimeter.len() == 0
        {
          has_empty_delimeter = true;
        }
      }
      closests.push( delimeter_next( &o.src, delimeter, &mut found_delimeters, position ) );
    }

    let mut delimeter = "";
    while position < src_len || position == 0
    {
      delimeter = closest_which( &o.src, &found_delimeters, &closests, &mut closest_position, &mut closest_index );

      if closest_position == src_len
      {
        break;
      }

      let del_len = delimeter.len();
      if del_len == 0
      {
        closest_position += 1;
      }

      let substring = o.src.get( position..closest_position ).unwrap();
      if preserving_empty || !substring.is_empty()
      {
        result.push( &substring );
      }

      if del_len > 0 || position < src_len
      {
        if preserving_delimeters
        {
          if preserving_empty || del_len > 0
          {
            result.push( delimeter );
          }
        }
      }

      position = closests[ closest_index as usize ] + ( if del_len > 0 { del_len } else { 1 } );

      for d in 0..delimeter_len
      {
        if closests[ d ] < position
        {
          closests[ d ] = delimeter_next( &o.src, delimeters[ d ], &mut found_delimeters, position );
        }
      }
    }

    if delimeter.len() > 0 || !has_empty_delimeter
    {
      let substring = o.src.get( position..src_len ).unwrap();
      if preserving_empty || !substring.is_empty()
      {
        result.push( &substring );
      }
    }

    if has_empty_delimeter
    {
      if result.len() > 0 && result[ result.len() - 1 ].is_empty()
      {
        result.pop();
      }
    }
  }

  return result;

  /* */

  fn delimeter_next( src : &String, delimeter : &str, found_delimeters : &mut Vec<&str>, position : usize ) -> usize
  {
    assert!( position <= src.len() );

    if regexp_is( delimeter )
    {
      unimplemented!( "regexp splitting is not implemented" );
    }
    else
    {
      let indexes: Vec<( usize, &str )> = src.match_indices( delimeter ).collect();
      for ( index, _ ) in indexes
      {
        if index >= position
        {
          return index;
        }
      }
    }

    src.len()
  }

  //

  fn closest_which<'a>( src : &String, found_delimeters : &Vec<&'a str>, closests : &Vec<usize>, closest_position : &mut usize, closest_index : &mut i32  ) -> &'a str
  {
    let src_len = src.len();
    *closest_position = src_len;
    *closest_index = 0;
    for d in 0..found_delimeters.len()
    {
      if closests[ d ] < src_len && closests[ d ] < *closest_position
      {
        *closest_position = closests[ d ];
        *closest_index = d as i32;
      }
    }

    found_delimeters[ *closest_index as usize ]
  }
}
<commit_msg>Implement builder methods for structure `split`<commit_after>#![ allow( dead_code ) ]
#![ allow( unused_variables ) ]
#![ allow( non_camel_case_types ) ]

use regex::Regex;

pub fn regexp_is( src : &str ) -> bool
{
  let regexp = Regex::new(r"^\\/.*\\/[dgimsuUx]").unwrap();
  regexp.is_match( src )
}

//

pub struct split<'a>
{
  pub src : String,
  pub delimeter : Vec<&'a str>,
  pub preserving_empty : bool,
  pub preserving_delimeters : bool,
  pub preserving_quoting : bool,
  pub inlining_quoting : bool,
  pub stripping : bool,
  pub quoting : bool,
  pub quoting_prefixes : Vec<&'a str>,
  pub quoting_postfixes : Vec<&'a str>,
  pub on_delimeter : Option<fn( &'a str, usize, &'a str ) -> &'a str>,
  pub on_quote : Option<fn( &'a str, usize, &'a str ) -> &'a str>,
  formed : u8,
}

impl<'a> Default for split<'a>
{
  fn default() -> Self
  {
    let opts = Self
    {
      src : String::from( "" ),
      delimeter : vec![ " " ],
      preserving_empty : true,
      preserving_delimeters : true,
      preserving_quoting : true,
      inlining_quoting : true,
      stripping : true,
      quoting : true,
      quoting_prefixes : vec![ "\"" ],
      quoting_postfixes : vec![ "\"" ],
      on_delimeter : None,
      on_quote : None,
      formed : 0,
    };
    return opts;
  }
}

impl<'a> split<'a> /* Dmytro : dubious, need to use traits */
{
  pub fn src( &mut self, src : String ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.src = src;
    self
  }

  //

  pub fn delimeter( &mut self, delimeter : Vec<&'a str> ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.delimeter = delimeter;
    self
  }

  //

  pub fn preserving_empty( &mut self, preserving_empty : bool ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.preserving_empty = preserving_empty;
    self
  }

  //

  pub fn preserving_delimeters( &mut self, preserving_delimeters : bool ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.preserving_delimeters = preserving_delimeters;
    self
  }

  //

  pub fn preserving_quoting( &mut self, preserving_quoting : bool ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.preserving_quoting = preserving_quoting;
    self
  }

  //

  pub fn inlining_quoting( &mut self, inlining_quoting : bool ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.inlining_quoting = inlining_quoting;
    self
  }

  //

  pub fn stripping( &mut self, stripping : bool ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.stripping = stripping;
    self
  }

  //

  pub fn quoting( &mut self, quoting : bool ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.quoting = quoting;
    self
  }

  //

  pub fn quoting_prefixes( &mut self, quoting_prefixes : Vec<&'a str> ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.quoting_prefixes = quoting_prefixes;
    self
  }

  //

  pub fn quoting_postfixes( &mut self, quoting_postfixes : Vec<&'a str> ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.quoting_postfixes = quoting_postfixes;
    self
  }

  //

  pub fn on_delimeter( &mut self, on_delimeter : fn( &'a str, usize, &'a str ) -> &'a str ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.on_delimeter = Some( on_delimeter );
    self
  }

  //

  pub fn on_quote( &mut self, on_quote : fn( &'a str, usize, &'a str ) -> &'a str ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.on_quote = Some( on_quote );
    self
  }

  //

  pub fn form( self ) -> Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    Self { formed : 1, .. self }
  }
}

//

#[derive(Debug, Clone)]
pub struct split_fast<'a>
{
  pub src : String,
  pub delimeter : Vec<&'a str>,
  pub preserving_empty : bool,
  pub preserving_delimeters : bool,
  formed : u8,
}

impl<'a> Default for split_fast<'a>
{
  fn default() -> Self
  {
    let opts = Self
    {
      src : String::from( "" ),
      delimeter : vec![ " " ],
      preserving_empty : true,
      preserving_delimeters : true,
      formed : 0,
    };
    opts
  }
}

impl<'a> split_fast<'a>
{
  pub fn src( &mut self, src : String ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.src = src;
    self
  }

  //

  pub fn delimeter( &mut self, delimeter : Vec<&'a str> ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.delimeter = delimeter;
    self
  }

  //

  pub fn preserving_empty( &mut self, preserving_empty : bool ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.preserving_empty = preserving_empty;
    self
  }

  //

  pub fn preserving_delimeters( &mut self, preserving_delimeters : bool ) -> &mut Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    self.preserving_delimeters = preserving_delimeters;
    self
  }

  //

  pub fn form( self ) -> Self
  {
    assert!( self.formed == 0, "Context is already formed" );
    Self { formed : 1, .. self }
  }
}

//

pub fn split_fast<'a>( o : &'a split_fast ) -> Vec<&'a str>
{
  let mut result: Vec<&str> = vec![];

  let delimeters = &o.delimeter;

  let preserving_empty = o.preserving_empty;
  let preserving_delimeters = o.preserving_delimeters;

  let mut found_delimeters = delimeters.clone();

  if !preserving_delimeters && delimeters.len() == 1
  {
    result = o.src.split( delimeters[ 0 ] ).collect();
    if !preserving_empty
    {
      result = result.iter().filter( | x | x.len() != 0 ).map( | x | *x ).collect::<Vec<_>>();
    }
  }
  else
  {
    let src_len = o.src.len();
    let delimeter_len = delimeters.len();
    if delimeter_len == 0
    {
      result.push( &*o.src );
      return result;
    }

    let mut closests : Vec<usize> = vec![];
    let mut position : usize = 0;
    let mut closest_position : usize = 0;
    let mut closest_index : i32 = -1;
    let mut has_empty_delimeter : bool = false;

    for d in 0..delimeter_len
    {
      let delimeter = delimeters[ d ];
      if regexp_is( delimeter )
      {
        unimplemented!( "regexp splitting is not implemented" );
      }
      else
      {
        if delimeter.len() == 0
        {
          has_empty_delimeter = true;
        }
      }
      closests.push( delimeter_next( &o.src, delimeter, &mut found_delimeters, position ) );
    }

    let mut delimeter = "";
    while position < src_len || position == 0
    {
      delimeter = closest_which( &o.src, &found_delimeters, &closests, &mut closest_position, &mut closest_index );

      if closest_position == src_len
      {
        break;
      }

      let del_len = delimeter.len();
      if del_len == 0
      {
        closest_position += 1;
      }

      let substring = o.src.get( position..closest_position ).unwrap();
      if preserving_empty || !substring.is_empty()
      {
        result.push( &substring );
      }

      if del_len > 0 || position < src_len
      {
        if preserving_delimeters
        {
          if preserving_empty || del_len > 0
          {
            result.push( delimeter );
          }
        }
      }

      position = closests[ closest_index as usize ] + ( if del_len > 0 { del_len } else { 1 } );

      for d in 0..delimeter_len
      {
        if closests[ d ] < position
        {
          closests[ d ] = delimeter_next( &o.src, delimeters[ d ], &mut found_delimeters, position );
        }
      }
    }

    if delimeter.len() > 0 || !has_empty_delimeter
    {
      let substring = o.src.get( position..src_len ).unwrap();
      if preserving_empty || !substring.is_empty()
      {
        result.push( &substring );
      }
    }

    if has_empty_delimeter
    {
      if result.len() > 0 && result[ result.len() - 1 ].is_empty()
      {
        result.pop();
      }
    }
  }

  return result;

  /* */

  fn delimeter_next( src : &String, delimeter : &str, found_delimeters : &mut Vec<&str>, position : usize ) -> usize
  {
    assert!( position <= src.len() );

    if regexp_is( delimeter )
    {
      unimplemented!( "regexp splitting is not implemented" );
    }
    else
    {
      let indexes: Vec<( usize, &str )> = src.match_indices( delimeter ).collect();
      for ( index, _ ) in indexes
      {
        if index >= position
        {
          return index;
        }
      }
    }

    src.len()
  }

  //

  fn closest_which<'a>( src : &String, found_delimeters : &Vec<&'a str>, closests : &Vec<usize>, closest_position : &mut usize, closest_index : &mut i32  ) -> &'a str
  {
    let src_len = src.len();
    *closest_position = src_len;
    *closest_index = 0;
    for d in 0..found_delimeters.len()
    {
      if closests[ d ] < src_len && closests[ d ] < *closest_position
      {
        *closest_position = closests[ d ];
        *closest_index = d as i32;
      }
    }

    found_delimeters[ *closest_index as usize ]
  }
}
<|endoftext|>


<commit_before>//! Implementation of the Xenstore protocol

use core::result;
use core::str::FromStr;

use ffi::CString;

use cell::GlobalCell;

use self::imp::XenStoreImpl;

use hal::xen::defs::{XenstoreInterface, EvtchnPort};

pub use self::transaction::Transaction;

static STORE: GlobalCell<XenStoreImpl> = GlobalCell::new();

mod imp;
mod transaction;

/// Result of an operation within the Xen Store
pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
/// Error code that can be returned by a Xen Store operation
pub enum Error {
    /// Unknown error happened
    Unknown,
    /// A type conversion error
    Conversion,
    /// Invalid argument
    Inval,
    /// Permission denied
    Acces,
    /// File exists
    Exist,
    /// Is a directory
    Isdir,
    /// No such file or directory
    Noent,
    /// Out of memory
    Nomem,
    /// No space left on device
    Nospc,
    /// I/O error
    Io,
    /// Directory not empty
    Notempty,
    /// Function not implemented
    Nosys,
    /// Read-only filesystem
    Rofs,
    /// Device or resource is busy
    Busy,
    /// Try again
    Again,
    /// Transport endpoint is already connected
    Isconn,
}

/// Main interface of the Xen Store
pub struct XenStore;

impl XenStore {
    #[doc(hidden)]
    pub unsafe fn init(interface: *mut XenstoreInterface, port: EvtchnPort) {
        STORE.set(XenStoreImpl::new(interface, port));
    }

    #[doc(hidden)]
    pub unsafe fn init_event() {
        STORE.as_mut().init_event();
    }

    /// Start a new transaction within the Xen Store
    pub fn start_transaction<'a>() -> Result<Transaction<'a>> {
        Transaction::new(STORE.as_mut())
    }

    /// Read a value from the xen store and convert it
    pub fn read_value<T: FromStr>(path: CString) -> Result<T> {
        let mut t = try!(Self::start_transaction());

        let val = try!(t.read(path));

        T::from_str(val.as_str()).or_else(|_| Err(Error::Conversion))
    }
}
<commit_msg>xen/store: read_value() now properly closes the transaction<commit_after>//! Implementation of the Xenstore protocol

use core::result;
use core::str::FromStr;

use ffi::CString;

use cell::GlobalCell;

use self::imp::XenStoreImpl;

use hal::xen::defs::{XenstoreInterface, EvtchnPort};

pub use self::transaction::Transaction;

static STORE: GlobalCell<XenStoreImpl> = GlobalCell::new();

mod imp;
mod transaction;

/// Result of an operation within the Xen Store
pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
/// Error code that can be returned by a Xen Store operation
pub enum Error {
    /// Unknown error happened
    Unknown,
    /// A type conversion error
    Conversion,
    /// Invalid argument
    Inval,
    /// Permission denied
    Acces,
    /// File exists
    Exist,
    /// Is a directory
    Isdir,
    /// No such file or directory
    Noent,
    /// Out of memory
    Nomem,
    /// No space left on device
    Nospc,
    /// I/O error
    Io,
    /// Directory not empty
    Notempty,
    /// Function not implemented
    Nosys,
    /// Read-only filesystem
    Rofs,
    /// Device or resource is busy
    Busy,
    /// Try again
    Again,
    /// Transport endpoint is already connected
    Isconn,
}

/// Main interface of the Xen Store
pub struct XenStore;

impl XenStore {
    #[doc(hidden)]
    pub unsafe fn init(interface: *mut XenstoreInterface, port: EvtchnPort) {
        STORE.set(XenStoreImpl::new(interface, port));
    }

    #[doc(hidden)]
    pub unsafe fn init_event() {
        STORE.as_mut().init_event();
    }

    /// Start a new transaction within the Xen Store
    pub fn start_transaction<'a>() -> Result<Transaction<'a>> {
        Transaction::new(STORE.as_mut())
    }

    /// Read a value from the xen store and convert it
    pub fn read_value<T: FromStr>(path: CString) -> Result<T> {
        let mut t = try!(Self::start_transaction());

        let val = try!(t.read(path));

        try!(t.end());

        T::from_str(val.as_str()).or_else(|_| Err(Error::Conversion))
    }
}
<|endoftext|>


<commit_before>//! A Collection of Header implementations for common HTTP Headers.
//!
//! ## Mime
//!
//! Several header fields use MIME values for their contents. Keeping with the
//! strongly-typed theme, the [mime](http://seanmonstar.github.io/mime.rs) crate
//! is used, such as `ContentType(pub Mime)`.

pub use self::accept::Accept;
pub use self::authorization::Authorization;
pub use self::cache_control::CacheControl;
pub use self::cookie::Cookies;
pub use self::connection::Connection;
pub use self::content_length::ContentLength;
pub use self::content_type::ContentType;
pub use self::date::Date;
pub use self::expires::Expires;
pub use self::host::Host;
pub use self::last_modified::LastModified;
pub use self::location::Location;
pub use self::transfer_encoding::TransferEncoding;
pub use self::upgrade::Upgrade;
pub use self::user_agent::UserAgent;
pub use self::server::Server;
pub use self::set_cookie::SetCookie;

macro_rules! bench_header(
    ($name:ident, $ty:ty, $value:expr) => {
        #[cfg(test)]
        mod $name {
            use test::Bencher;
            use super::*;

            use header::{Header, HeaderFormatter};

            #[bench]
            fn bench_parse(b: &mut Bencher) {
                let val = $value;
                b.iter(|| {
                    let _: $ty = Header::parse_header(val[]).unwrap();
                });
            }

            #[bench]
            fn bench_format(b: &mut Bencher) {
                let val: $ty = Header::parse_header($value[]).unwrap();
                let fmt = HeaderFormatter(&val);
                b.iter(|| {
                    format!("{}", fmt);
                });
            }
        }
    }
)

macro_rules! deref(
    ($from:ty -> $to:ty) => {
        impl Deref<$to> for $from {
            fn deref<'a>(&'a self) -> &'a $to {
                &self.0
            }
        }

        impl DerefMut<$to> for $from {
            fn deref_mut<'a>(&'a mut self) -> &'a mut $to {
                &mut self.0
            }
        }
    }
)

/// Exposes the Accept header.
pub mod accept;

/// Exposes the Authorization header.
pub mod authorization;

/// Exposes the CacheControl header.
pub mod cache_control;

/// Exposes the Cookie header.
pub mod cookie;

/// Exposes the Connection header.
pub mod connection;

/// Exposes the ContentLength header.
pub mod content_length;

/// Exposes the ContentType header.
pub mod content_type;

/// Exposes the Date header.
pub mod date;

/// Exposes the Expires header.
pub mod expires;

/// Exposes the Host header.
pub mod host;

/// Exposes the LastModified header.
pub mod last_modified;

/// Exposes the If-Modified-Since header.
pub mod if_modified_since;

/// Exposes the Location header.
pub mod location;

/// Exposes the Server header.
pub mod server;

/// Exposes the Set-Cookie header.
pub mod set_cookie;

/// Exposes the TransferEncoding header.
pub mod transfer_encoding;

/// Exposes the Upgrade header.
pub mod upgrade;

/// Exposes the UserAgent header.
pub mod user_agent;

pub mod util;
<commit_msg>Add missing reexport<commit_after>//! A Collection of Header implementations for common HTTP Headers.
//!
//! ## Mime
//!
//! Several header fields use MIME values for their contents. Keeping with the
//! strongly-typed theme, the [mime](http://seanmonstar.github.io/mime.rs) crate
//! is used, such as `ContentType(pub Mime)`.

pub use self::accept::Accept;
pub use self::authorization::Authorization;
pub use self::cache_control::CacheControl;
pub use self::cookie::Cookies;
pub use self::connection::Connection;
pub use self::content_length::ContentLength;
pub use self::content_type::ContentType;
pub use self::date::Date;
pub use self::expires::Expires;
pub use self::host::Host;
pub use self::last_modified::LastModified;
pub use self::if_modified_since::IfModifiedSince;
pub use self::location::Location;
pub use self::transfer_encoding::TransferEncoding;
pub use self::upgrade::Upgrade;
pub use self::user_agent::UserAgent;
pub use self::server::Server;
pub use self::set_cookie::SetCookie;

macro_rules! bench_header(
    ($name:ident, $ty:ty, $value:expr) => {
        #[cfg(test)]
        mod $name {
            use test::Bencher;
            use super::*;

            use header::{Header, HeaderFormatter};

            #[bench]
            fn bench_parse(b: &mut Bencher) {
                let val = $value;
                b.iter(|| {
                    let _: $ty = Header::parse_header(val[]).unwrap();
                });
            }

            #[bench]
            fn bench_format(b: &mut Bencher) {
                let val: $ty = Header::parse_header($value[]).unwrap();
                let fmt = HeaderFormatter(&val);
                b.iter(|| {
                    format!("{}", fmt);
                });
            }
        }
    }
)

macro_rules! deref(
    ($from:ty -> $to:ty) => {
        impl Deref<$to> for $from {
            fn deref<'a>(&'a self) -> &'a $to {
                &self.0
            }
        }

        impl DerefMut<$to> for $from {
            fn deref_mut<'a>(&'a mut self) -> &'a mut $to {
                &mut self.0
            }
        }
    }
)

/// Exposes the Accept header.
pub mod accept;

/// Exposes the Authorization header.
pub mod authorization;

/// Exposes the CacheControl header.
pub mod cache_control;

/// Exposes the Cookie header.
pub mod cookie;

/// Exposes the Connection header.
pub mod connection;

/// Exposes the ContentLength header.
pub mod content_length;

/// Exposes the ContentType header.
pub mod content_type;

/// Exposes the Date header.
pub mod date;

/// Exposes the Expires header.
pub mod expires;

/// Exposes the Host header.
pub mod host;

/// Exposes the LastModified header.
pub mod last_modified;

/// Exposes the If-Modified-Since header.
pub mod if_modified_since;

/// Exposes the Location header.
pub mod location;

/// Exposes the Server header.
pub mod server;

/// Exposes the Set-Cookie header.
pub mod set_cookie;

/// Exposes the TransferEncoding header.
pub mod transfer_encoding;

/// Exposes the Upgrade header.
pub mod upgrade;

/// Exposes the UserAgent header.
pub mod user_agent;

pub mod util;
<|endoftext|>


<commit_before>use std::cell::Cell;

use ast::Ast;
use ast::Elem::{self, ElemFunction};
use ast::Expr::{self, ExprUn, ExprBin, ExprLitInt, ExprLitStr, ExprLitBool,
                ExprAssign, ExprIdent};
use ast::ExprUnType;
use ast::ExprBinType;
use ast::ExprLitIntType;
use ast::ExprLitStrType;
use ast::ExprLitBoolType;
use ast::ExprIdentType;
use ast::ExprAssignType;
use ast::Function;
use ast::Stmt::{self, StmtBlock, StmtBreak, StmtContinue, StmtExpr,
                StmtIf, StmtReturn};
use ast::StmtBlockType;
use ast::StmtBreakType;
use ast::StmtContinueType;
use ast::StmtExprType;
use ast::StmtIfType;
use ast::StmtReturnType;
use ast::Type::{self, TypeBasic, TypeUnit};
use interner::Name;

macro_rules! dump {
    ($self_:ident, $($x:expr),*) => {{
        for _ in 0..($self_.indent*2) {
            print!(" ");
        }

        println!($($x,)*);
    }};
}

pub struct AstDumper<'a> {
    ast: &'a Ast,
    indent: u32,
}

impl<'a> AstDumper<'a> {
    pub fn new(ast: &Ast) -> AstDumper {
        AstDumper {
            ast: ast,
            indent: 0
        }
    }

    pub fn dump(&mut self) {
        for el in &self.ast.elements {
            match *el {
                ElemFunction(ref fct) => self.dump_fct(fct),
                _ => unreachable!()
            }
        }
    }

    fn dump_fct(&mut self, fct: &Function) {
        dump!(self, "fct {} @ {}", self.str(fct.name), fct.pos);

        self.indent(|d| {
            if(fct.params.is_empty()) {
                dump!(d, "no params");
            } else {
                for param in &fct.params {
                    dump!(d, "param {} @ {}", d.str(param.name), param.pos);
                    d.indent(|d| d.dump_type(&param.data_type));
                }
            }
        });

        dump!(self, "fct {} returns", self.str(fct.name));
        self.indent(|d| d.dump_type(&fct.return_type));

        dump!(self, "fct {} executes", self.str(fct.name));
        self.indent(|d| d.dump_stmt(&fct.block));
    }

    fn dump_type(&mut self, ty: &Type) {
        match *ty {
            TypeBasic(name) => dump!(self, "type {}", self.str(name)),
            TypeUnit => dump!(self, "type () / void")
        }
    }

    fn dump_stmt(&mut self, stmt: &Stmt) {
        match *stmt {
            StmtBlock(ref block) => self.dump_stmt_block(block),
            StmtReturn(ref ret) => self.dump_stmt_return(ret),
            StmtBreak(ref stmt) => self.dump_stmt_break(stmt),
            StmtContinue(ref stmt) => self.dump_stmt_continue(stmt),
            StmtExpr(ref expr) => self.dump_stmt_expr(expr),
            StmtIf(ref stmt) => self.dump_stmt_if(stmt),
            _ => unimplemented!()
        }
    }

    fn dump_stmt_if(&mut self, stmt: &StmtIfType) {
        dump!(self, "if @ {}", stmt.pos);

        self.indent(|d| {
            d.indent(|d| { d.dump_expr(&stmt.cond); });
            dump!(d, "then");
            d.indent(|d| { d.dump_stmt(&stmt.then_block); });
            dump!(d, "else");
            d.indent(|d| { d.dump_stmt(&stmt.then_block); });
        });
    }

    fn dump_stmt_expr(&mut self, stmt: &StmtExprType) {
        dump!(self, "expr stmt @ {}", stmt.pos);
        self.indent(|d| { d.dump_expr(&stmt.expr); });
    }

    fn dump_stmt_block(&mut self, block: &StmtBlockType) {
        dump!(self, "block ({} statements) @ {}", block.stmts.len(), block.pos);

        self.indent(|d| {
            if(block.stmts.is_empty()) {
                dump!(d, "no statements");
            } else {
                for stmt in &block.stmts {
                    d.dump_stmt(stmt);
                }
            }
        });

        dump!(self, "block end");
    }

    fn dump_stmt_return(&mut self, ret: &StmtReturnType) {
        if let Some(ref expr) = ret.expr {
            dump!(self, "return @ {}", ret.pos);
            self.indent(|d| d.dump_expr(expr));
        } else {
            dump!(self, "return void @ {}", ret.pos);
        }
    }

    fn dump_stmt_break(&mut self, stmt: &StmtBreakType) {
        dump!(self, "break @ {}", stmt.pos);
    }

    fn dump_stmt_continue(&mut self, stmt: &StmtContinueType) {
        dump!(self, "break @ {}", stmt.pos);
    }

    fn dump_expr(&mut self, expr: &Expr) {
        match *expr {
            ExprUn(ref un) => self.dump_expr_un(un),
            ExprBin(ref bin) => self.dump_expr_bin(bin),
            ExprLitInt(ref lit) => dump!(self, "lit int {}", lit.value),
            ExprLitStr(ref lit) => dump!(self, "lit string {:?}", lit.value),
            ExprLitBool(ref lit) => dump!(self, "lit bool {}", lit.value),
            ExprIdent(ref ident) => dump!(self, "ident {}", self.str(ident.name)),
            ExprAssign(ref assign) => self.dump_expr_assign(assign),
        }
    }

    fn dump_expr_un(&mut self, expr: &ExprUnType) {
        dump!(self, "unary {:?}", expr.op);
        self.indent(|d| d.dump_expr(&expr.opnd));
    }

    fn dump_expr_bin(&mut self, expr: &ExprBinType) {
        self.indent(|d| d.dump_expr(&expr.rhs));
        dump!(self, "binary {:?}", expr.op);
        self.indent(|d| d.dump_expr(&expr.lhs));
    }

    fn dump_expr_assign(&mut self, expr: &ExprAssignType) {
        self.indent(|d| d.dump_expr(&expr.rhs));
        dump!(self, "assign (=)");
        self.indent(|d| d.dump_expr(&expr.lhs));
    }

    fn indent<F>(&mut self, fct: F) where F: Fn(&mut AstDumper) -> () {
        let old = self.indent;
        self.indent = old+1;

        fct(self);

        self.indent = old;
    }

    fn str(&self, name: Name) -> &str {
        self.ast.str(name)
    }
}
<commit_msg>implemented all statements for dumper<commit_after>use std::cell::Cell;

use ast::Ast;
use ast::Elem::{self, ElemFunction};
use ast::Expr::{self, ExprUn, ExprBin, ExprLitInt, ExprLitStr, ExprLitBool,
                ExprAssign, ExprIdent};
use ast::ExprUnType;
use ast::ExprBinType;
use ast::ExprLitIntType;
use ast::ExprLitStrType;
use ast::ExprLitBoolType;
use ast::ExprIdentType;
use ast::ExprAssignType;
use ast::Function;
use ast::Stmt::{self, StmtBlock, StmtBreak, StmtContinue, StmtExpr,
                StmtIf, StmtLoop, StmtReturn, StmtVar, StmtWhile};
use ast::StmtBlockType;
use ast::StmtBreakType;
use ast::StmtContinueType;
use ast::StmtExprType;
use ast::StmtIfType;
use ast::StmtLoopType;
use ast::StmtReturnType;
use ast::StmtVarType;
use ast::StmtWhileType;
use ast::Type::{self, TypeBasic, TypeUnit};
use interner::Name;

macro_rules! dump {
    ($self_:ident, $($x:expr),*) => {{
        for _ in 0..($self_.indent*2) {
            print!(" ");
        }

        println!($($x,)*);
    }};
}

pub struct AstDumper<'a> {
    ast: &'a Ast,
    indent: u32,
}

impl<'a> AstDumper<'a> {
    pub fn new(ast: &Ast) -> AstDumper {
        AstDumper {
            ast: ast,
            indent: 0
        }
    }

    pub fn dump(&mut self) {
        for el in &self.ast.elements {
            match *el {
                ElemFunction(ref fct) => self.dump_fct(fct),
                _ => unreachable!()
            }
        }
    }

    fn dump_fct(&mut self, fct: &Function) {
        dump!(self, "fct {} @ {}", self.str(fct.name), fct.pos);

        self.indent(|d| {
            if(fct.params.is_empty()) {
                dump!(d, "no params");
            } else {
                for param in &fct.params {
                    dump!(d, "param {} @ {}", d.str(param.name), param.pos);
                    d.indent(|d| d.dump_type(&param.data_type));
                }
            }
        });

        dump!(self, "fct {} returns", self.str(fct.name));
        self.indent(|d| d.dump_type(&fct.return_type));

        dump!(self, "fct {} executes", self.str(fct.name));
        self.indent(|d| d.dump_stmt(&fct.block));
    }

    fn dump_type(&mut self, ty: &Type) {
        match *ty {
            TypeBasic(name) => dump!(self, "type {}", self.str(name)),
            TypeUnit => dump!(self, "type () / void")
        }
    }

    fn dump_stmt(&mut self, stmt: &Stmt) {
        match *stmt {
            StmtBlock(ref block) => self.dump_stmt_block(block),
            StmtReturn(ref ret) => self.dump_stmt_return(ret),
            StmtBreak(ref stmt) => self.dump_stmt_break(stmt),
            StmtContinue(ref stmt) => self.dump_stmt_continue(stmt),
            StmtExpr(ref expr) => self.dump_stmt_expr(expr),
            StmtIf(ref stmt) => self.dump_stmt_if(stmt),
            StmtVar(ref stmt) => self.dump_stmt_var(stmt),
            StmtWhile(ref stmt) => self.dump_stmt_while(stmt),
            StmtLoop(ref stmt) => self.dump_stmt_loop(stmt),
        }
    }

    fn dump_stmt_var(&mut self, stmt: &StmtVarType) {
        dump!(self, "var {} @ {}", self.str(stmt.name), stmt.pos);

        self.indent(|d| {
            dump!(d, "expr");
            d.indent(|d| {
                if let Some(ref ty) = stmt.data_type {
                    d.dump_type(ty);
                } else {
                    dump!(d, "no type given")
                }
            });

            dump!(d, "type");
            d.indent(|d| {
                if let Some(ref expr) = stmt.expr {
                    d.dump_expr(expr);
                } else {
                    dump!(d, "no expr given")
                }
            });
        });
    }

    fn dump_stmt_while(&mut self, stmt: &StmtWhileType) {
        dump!(self, "while @ {}", stmt.pos);

        self.indent(|d| {
            dump!(d, "cond");
            d.indent(|d| { d.dump_expr(&stmt.cond); });

            dump!(d, "body");
            d.indent(|d| { d.dump_stmt(&stmt.block); });
        });
    }

    fn dump_stmt_loop(&mut self, stmt: &StmtLoopType) {
        dump!(self, "loop @ {}", stmt.pos);
        self.indent(|d| { d.dump_stmt(&stmt.block); });
    }

    fn dump_stmt_if(&mut self, stmt: &StmtIfType) {
        dump!(self, "if @ {}", stmt.pos);

        self.indent(|d| {
            d.indent(|d| { d.dump_expr(&stmt.cond); });
            dump!(d, "then");
            d.indent(|d| { d.dump_stmt(&stmt.then_block); });
            dump!(d, "else");
            d.indent(|d| { d.dump_stmt(&stmt.then_block); });
        });
    }

    fn dump_stmt_expr(&mut self, stmt: &StmtExprType) {
        dump!(self, "expr stmt @ {}", stmt.pos);
        self.indent(|d| { d.dump_expr(&stmt.expr); });
    }

    fn dump_stmt_block(&mut self, block: &StmtBlockType) {
        dump!(self, "block ({} statements) @ {}", block.stmts.len(), block.pos);

        self.indent(|d| {
            if(block.stmts.is_empty()) {
                dump!(d, "no statements");
            } else {
                for stmt in &block.stmts {
                    d.dump_stmt(stmt);
                }
            }
        });

        dump!(self, "block end");
    }

    fn dump_stmt_return(&mut self, ret: &StmtReturnType) {
        if let Some(ref expr) = ret.expr {
            dump!(self, "return @ {}", ret.pos);
            self.indent(|d| d.dump_expr(expr));
        } else {
            dump!(self, "return void @ {}", ret.pos);
        }
    }

    fn dump_stmt_break(&mut self, stmt: &StmtBreakType) {
        dump!(self, "break @ {}", stmt.pos);
    }

    fn dump_stmt_continue(&mut self, stmt: &StmtContinueType) {
        dump!(self, "break @ {}", stmt.pos);
    }

    fn dump_expr(&mut self, expr: &Expr) {
        match *expr {
            ExprUn(ref un) => self.dump_expr_un(un),
            ExprBin(ref bin) => self.dump_expr_bin(bin),
            ExprLitInt(ref lit) => dump!(self, "lit int {}", lit.value),
            ExprLitStr(ref lit) => dump!(self, "lit string {:?}", lit.value),
            ExprLitBool(ref lit) => dump!(self, "lit bool {}", lit.value),
            ExprIdent(ref ident) => dump!(self, "ident {}", self.str(ident.name)),
            ExprAssign(ref assign) => self.dump_expr_assign(assign),
        }
    }

    fn dump_expr_un(&mut self, expr: &ExprUnType) {
        dump!(self, "unary {:?}", expr.op);
        self.indent(|d| d.dump_expr(&expr.opnd));
    }

    fn dump_expr_bin(&mut self, expr: &ExprBinType) {
        self.indent(|d| d.dump_expr(&expr.rhs));
        dump!(self, "binary {:?}", expr.op);
        self.indent(|d| d.dump_expr(&expr.lhs));
    }

    fn dump_expr_assign(&mut self, expr: &ExprAssignType) {
        self.indent(|d| d.dump_expr(&expr.rhs));
        dump!(self, "assign (=)");
        self.indent(|d| d.dump_expr(&expr.lhs));
    }

    fn indent<F>(&mut self, fct: F) where F: Fn(&mut AstDumper) -> () {
        let old = self.indent;
        self.indent = old+1;

        fct(self);

        self.indent = old;
    }

    fn str(&self, name: Name) -> &str {
        self.ast.str(name)
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

// TODO support reading from standard input

extern crate extra;
extern crate termion;

use std::env::args;
use std::fs::File;
use std::io::{self, Write, Read, StdoutLock, Stderr};
use std::path::Path;

use extra::option::OptionalExt;

use termion::{terminal_size, TermRead, TermWrite, IntoRawMode, Color, Key, RawTerminal};

static LONG_HELP: &'static str = r#"
    NAME
        less - view a text file.
    SYNOPSIS
        less [-h | --help] [input]
    DESCRIPTION
        This utility views text files. If no input file is specified as an argument, standard input is used.
    OPTIONS
        --help, -h
            Print this manual page.
    AUTHOR
        This program was written by MovingtoMars for Redox OS. Bugs, issues, or feature requests should be reported in the Github repository, 'redox-os/extrautils'.
    COPYRIGHT
        Copyright (c) 2016 MovingtoMars

        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"#;

fn main() {
    let mut args = args().skip(1);
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let stdin = io::stdin();
    let mut stdin = stdin.lock();
    let mut stderr = io::stderr();

    if let Some(x) = args.next() {
        match x.as_str() {
            "--help" | "-h" => {
                // Print help.
                stdout.write(LONG_HELP.as_bytes()).try(&mut stderr);
                return;
            },
            filename => {
                let mut file = File::open(Path::new(filename)).try(&mut stderr);
                run(&mut file, &mut stdin, &mut stdout, &mut stderr);
            }
        }

        if let Some(x) = args.next() {
            let mut file = File::open(Path::new(x.as_str())).try(&mut stderr);
            run(&mut file, &mut stdin, &mut stdout, &mut stderr);
        }
    } else {
        writeln!(stderr, "Readin from stdin is not yet supported").try(&mut stderr);
        //run(&mut stdin, &mut stdin, &mut stdout, &mut stderr);
    };
}

struct Buffer {
    lines: Vec<String>,
    y_off: u16,
}

impl Buffer {
    fn new() -> Buffer {
        Buffer{
            lines: Vec::new(),
            y_off: 0,
        }
    }

    fn read(&mut self, from: &mut Read) -> std::io::Result<usize> {
        let mut tmp = String::new();
        let res = from.read_to_string(&mut tmp);
        try!(res);

        self.lines.append(&mut tmp
            .as_str()
            .split("\n")
            .map(|x| {String::from(x)})
            .collect());

        return res;
    }

    fn draw(&self, to: &mut RawTerminal<&mut StdoutLock>, w: u16, h: u16) -> std::io::Result<usize> {
        try!(to.goto(0, 0));

        let mut y = 0;
        let mut bytes_written = 0;

        let lines = if self.lines.len() <= h as usize {
            &self.lines
        } else if self.y_off as usize >= self.lines.len() {
            &self.lines[0..0]
        } else {
            &self.lines[self.y_off as usize..]
        };

        for line in lines {
            if line.len() > w as usize {
                bytes_written += try!(to.write(line[..w as usize].as_bytes()));
            } else {
                bytes_written += try!(to.write(line.as_bytes()));
            }

            y += 1;
            try!(to.goto(0, y));
            if y >= h {
                break;
            }
        }

        Ok(bytes_written)
    }

    fn scroll_up(&mut self) {
        if self.y_off > 0 {
            self.y_off -= 1;
        }
    }

    fn scroll_down(&mut self, height: u16) {
        if ((self.y_off + height) as usize) <= self.lines.len() {
            self.y_off += 1;
        }
    }
}

fn run(file: &mut Read, controls: &mut Read, stdout: &mut StdoutLock, stderr: &mut Stderr) {
    let mut stdout = stdout.into_raw_mode().try(stderr);

    let (w, h) = {
        let (w, h) = terminal_size().try(stderr);
        (w as u16, h as u16)
    };

    stdout.clear().try(stderr);
    stdout.reset().try(stderr);

    let mut buffer = Buffer::new();
    buffer.read(file).try(stderr);

    buffer.draw(&mut stdout, w, h - 1).try(stderr);
    stdout.goto(0, h - 1).try(stderr);
    stdout.bg_color(Color::White).try(stderr);
    stdout.color(Color::Black).try(stderr);
    stdout.write(b"Press q to exit.").try(stderr);
    stdout.reset().try(stderr);
    stdout.flush().try(stderr);

    for c in controls.keys() {
        match c {
            Key::Char('q') => {
                stdout.clear().try(stderr);
                stdout.reset().try(stderr);
                stdout.goto(0, 0).try(stderr);
                return
            },
            Key::Up => buffer.scroll_up(),
            Key::Down => buffer.scroll_down(h),
            _ => {},
        }

        stdout.clear().try(stderr);
        stdout.reset().try(stderr);
        buffer.draw(&mut stdout, w, h - 1).try(stderr);
        stdout.goto(0, h - 1).try(stderr);
        stdout.bg_color(Color::White).try(stderr);
        stdout.color(Color::Black).try(stderr);
        stdout.write(b"Press q to exit.").try(stderr);
        stdout.reset().try(stderr);
        stdout.flush().try(stderr);
    }
}
<commit_msg>Add aliases for up and down in 'less'<commit_after>#![deny(warnings)]

// TODO support reading from standard input

extern crate extra;
extern crate termion;

use std::env::args;
use std::fs::File;
use std::io::{self, Write, Read, StdoutLock, Stderr};
use std::path::Path;

use extra::option::OptionalExt;

use termion::{terminal_size, TermRead, TermWrite, IntoRawMode, Color, Key, RawTerminal};

static LONG_HELP: &'static str = r#"
    NAME
        less - view a text file.
    SYNOPSIS
        less [-h | --help] [input]
    DESCRIPTION
        This utility views text files. If no input file is specified as an argument, standard input is used.
    OPTIONS
        --help, -h
            Print this manual page.
    AUTHOR
        This program was written by MovingtoMars for Redox OS. Bugs, issues, or feature requests should be reported in the Github repository, 'redox-os/extrautils'.
    COPYRIGHT
        Copyright (c) 2016 MovingtoMars

        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"#;

fn main() {
    let mut args = args().skip(1);
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let stdin = io::stdin();
    let mut stdin = stdin.lock();
    let mut stderr = io::stderr();

    if let Some(x) = args.next() {
        match x.as_str() {
            "--help" | "-h" => {
                // Print help.
                stdout.write(LONG_HELP.as_bytes()).try(&mut stderr);
                return;
            },
            filename => {
                let mut file = File::open(Path::new(filename)).try(&mut stderr);
                run(&mut file, &mut stdin, &mut stdout, &mut stderr);
            }
        }

        if let Some(x) = args.next() {
            let mut file = File::open(Path::new(x.as_str())).try(&mut stderr);
            run(&mut file, &mut stdin, &mut stdout, &mut stderr);
        }
    } else {
        writeln!(stderr, "Readin from stdin is not yet supported").try(&mut stderr);
        //run(&mut stdin, &mut stdin, &mut stdout, &mut stderr);
    };
}

struct Buffer {
    lines: Vec<String>,
    y_off: u16,
}

impl Buffer {
    fn new() -> Buffer {
        Buffer{
            lines: Vec::new(),
            y_off: 0,
        }
    }

    fn read(&mut self, from: &mut Read) -> std::io::Result<usize> {
        let mut tmp = String::new();
        let res = from.read_to_string(&mut tmp);
        try!(res);

        self.lines.append(&mut tmp
            .as_str()
            .split("\n")
            .map(|x| {String::from(x)})
            .collect());

        return res;
    }

    fn draw(&self, to: &mut RawTerminal<&mut StdoutLock>, w: u16, h: u16) -> std::io::Result<usize> {
        try!(to.goto(0, 0));

        let mut y = 0;
        let mut bytes_written = 0;

        let lines = if self.lines.len() <= h as usize {
            &self.lines
        } else if self.y_off as usize >= self.lines.len() {
            &self.lines[0..0]
        } else {
            &self.lines[self.y_off as usize..]
        };

        for line in lines {
            if line.len() > w as usize {
                bytes_written += try!(to.write(line[..w as usize].as_bytes()));
            } else {
                bytes_written += try!(to.write(line.as_bytes()));
            }

            y += 1;
            try!(to.goto(0, y));
            if y >= h {
                break;
            }
        }

        Ok(bytes_written)
    }

    fn scroll_up(&mut self) {
        if self.y_off > 0 {
            self.y_off -= 1;
        }
    }

    fn scroll_down(&mut self, height: u16) {
        if ((self.y_off + height) as usize) <= self.lines.len() {
            self.y_off += 1;
        }
    }
}

fn run(file: &mut Read, controls: &mut Read, stdout: &mut StdoutLock, stderr: &mut Stderr) {
    let mut stdout = stdout.into_raw_mode().try(stderr);

    let (w, h) = {
        let (w, h) = terminal_size().try(stderr);
        (w as u16, h as u16)
    };

    stdout.clear().try(stderr);
    stdout.reset().try(stderr);

    let mut buffer = Buffer::new();
    buffer.read(file).try(stderr);

    buffer.draw(&mut stdout, w, h - 1).try(stderr);
    stdout.goto(0, h - 1).try(stderr);
    stdout.bg_color(Color::White).try(stderr);
    stdout.color(Color::Black).try(stderr);
    stdout.write(b"Press q to exit.").try(stderr);
    stdout.reset().try(stderr);
    stdout.flush().try(stderr);

    for c in controls.keys() {
        match c {
            Key::Char('q') => {
                stdout.clear().try(stderr);
                stdout.reset().try(stderr);
                stdout.goto(0, 0).try(stderr);
                return
            },
            Key::Up | Key::Char('k') => buffer.scroll_up(),
            Key::Down | Key::Char('j') => buffer.scroll_down(h),
            _ => {},
        }

        stdout.clear().try(stderr);
        stdout.reset().try(stderr);
        buffer.draw(&mut stdout, w, h - 1).try(stderr);
        stdout.goto(0, h - 1).try(stderr);
        stdout.bg_color(Color::White).try(stderr);
        stdout.color(Color::Black).try(stderr);
        stdout.write(b"Press q to exit.").try(stderr);
        stdout.reset().try(stderr);
        stdout.flush().try(stderr);
    }
}
<|endoftext|>


<commit_before>
use Color;

pub trait Buffer2d {
    fn width(&self) -> u32;
    fn height(&self) -> u32;

    fn get(&self, _x: u32, _y: u32) -> Option<Color> { unimplemented!() }
    fn set(&mut self, _x: u32, _y: u32, _val: Color) { unimplemented!() }

    fn patch(&mut self, x: u32, y: u32, buf: &Buffer2d) {
        let (w, h) = buf.dimensions();

        for sy in range(0, h) {
            for sx in range(0, w) {

                match buf.get(sx, sy) {
                    Some(val) => {
                        self.set(x + sx, y + sy, val);
                    },
                    _ => {},
                }
            }
        }
    }

    fn patch_rotated(&mut self, x: u32, y: u32, buf: &Buffer2d) {
        let (w, h) = buf.dimensions();

        for sy in range(0, h) {
            for sx in range(0, w) {
                match buf.get(sx, sy) {
                    Some(val) => {
                        self.set(x + h - sy - 1, y + sx, val);
                    },
                    _ => {},
                }
            }
        }
    }

    fn dimensions(&self) -> (u32, u32) {
        (self.width(), self.height())
    }
}

<commit_msg>remove unimplemented default trait methods<commit_after>use Color;

pub trait Buffer2d {
    fn width(&self) -> u32;
    fn height(&self) -> u32;

    fn get(&self, _x: u32, _y: u32) -> Option<Color>;
    fn set(&mut self, _x: u32, _y: u32, _val: Color);

    fn patch(&mut self, x: u32, y: u32, buf: &Buffer2d) {
        let (w, h) = buf.dimensions();

        for sy in range(0, h) {
            for sx in range(0, w) {

                match buf.get(sx, sy) {
                    Some(val) => {
                        self.set(x + sx, y + sy, val);
                    },
                    _ => {},
                }
            }
        }
    }

    fn patch_rotated(&mut self, x: u32, y: u32, buf: &Buffer2d) {
        let (w, h) = buf.dimensions();

        for sy in range(0, h) {
            for sx in range(0, w) {
                match buf.get(sx, sy) {
                    Some(val) => {
                        self.set(x + h - sy - 1, y + sx, val);
                    },
                    _ => {},
                }
            }
        }
    }

    fn dimensions(&self) -> (u32, u32) {
        (self.width(), self.height())
    }
}

<|endoftext|>


<commit_before>//! Cholesky decomposition

use ndarray::*;
use num_traits::Zero;

use super::convert::*;
use super::error::*;
use super::layout::*;
use super::triangular::IntoTriangular;

use lapack_traits::LapackScalar;
pub use lapack_traits::UPLO;

pub trait Cholesky<K> {
    fn cholesky(self, UPLO) -> Result<K>;
}

impl<A, S> Cholesky<ArrayBase<S, Ix2>> for ArrayBase<S, Ix2>
where
    A: LapackScalar + Zero,
    S: DataMut<Elem = A>,
{
    fn cholesky(mut self, uplo: UPLO) -> Result<ArrayBase<S, Ix2>> {
        A::cholesky(self.square_layout()?, uplo, self.as_allocated_mut()?)?;
        Ok(self.into_triangular(uplo))
    }
}

impl<'a, A, S> Cholesky<&'a mut ArrayBase<S, Ix2>> for &'a mut ArrayBase<S, Ix2>
where
    A: LapackScalar + Zero,
    S: DataMut<Elem = A>,
{
    fn cholesky(mut self, uplo: UPLO) -> Result<&'a mut ArrayBase<S, Ix2>> {
        A::cholesky(self.square_layout()?, uplo, self.as_allocated_mut()?)?;
        Ok(self.into_triangular(uplo))
    }
}

impl<'a, A, Si, So> Cholesky<ArrayBase<So, Ix2>> for &'a ArrayBase<Si, Ix2>
where
    A: LapackScalar + Copy + Zero,
    Si: Data<Elem = A>,
    So: DataMut<Elem = A> + DataOwned,
{
    fn cholesky(self, uplo: UPLO) -> Result<ArrayBase<So, Ix2>> {
        let mut a = replicate(self);
        A::cholesky(a.square_layout()?, uplo, a.as_allocated_mut()?)?;
        Ok(a.into_triangular(uplo))
    }
}
<commit_msg>Simplify Cholesky<commit_after>//! Cholesky decomposition

use ndarray::*;

use super::convert::*;
use super::error::*;
use super::layout::*;
use super::triangular::IntoTriangular;
use super::types::*;

pub use lapack_traits::UPLO;

pub trait Cholesky {
    type Output;
    fn cholesky(&self, UPLO) -> Result<Self::Output>;
}

pub trait CholeskyInto: Sized {
    fn cholesky_into(self, UPLO) -> Result<Self>;
}

pub trait CholeskyMut {
    fn cholesky_mut(&mut self, UPLO) -> Result<&mut Self>;
}

impl<A, S> CholeskyInto for ArrayBase<S, Ix2>
where
    A: Scalar,
    S: DataMut<Elem = A>,
{
    fn cholesky_into(mut self, uplo: UPLO) -> Result<Self> {
        A::cholesky(self.square_layout()?, uplo, self.as_allocated_mut()?)?;
        Ok(self.into_triangular(uplo))
    }
}

impl<A, S> CholeskyMut for ArrayBase<S, Ix2>
where
    A: Scalar,
    S: DataMut<Elem = A>,
{
    fn cholesky_mut(&mut self, uplo: UPLO) -> Result<&mut Self> {
        A::cholesky(self.square_layout()?, uplo, self.as_allocated_mut()?)?;
        Ok(self.into_triangular(uplo))
    }
}

impl<A, S> Cholesky for ArrayBase<S, Ix2>
where
    A: Scalar,
    S: Data<Elem = A>,
{
    type Output = Array2<A>;

    fn cholesky(&self, uplo: UPLO) -> Result<Self::Output> {
        let mut a = replicate(self);
        A::cholesky(a.square_layout()?, uplo, a.as_allocated_mut()?)?;
        Ok(a.into_triangular(uplo))
    }
}
<|endoftext|>