<commit_before>//! `cargo upgrade`
#![warn(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
        trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
        unused_qualifications)]

extern crate cargo_metadata;
extern crate docopt;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate serde_derive;
extern crate toml_edit;

use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::io::Write;
use std::process;

extern crate cargo_edit;
use cargo_edit::{find, get_latest_dependency, CrateName, Dependency, LocalManifest};

extern crate termcolor;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};

mod errors {
    error_chain!{
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
            CargoMetadata(::cargo_metadata::Error, ::cargo_metadata::ErrorKind);
        }
    }
}
use errors::*;

static USAGE: &'static str = r"
Upgrade dependencies as specified in the local manifest file (i.e. Cargo.toml).

Usage:
    cargo upgrade [options] [<dependency>]...
    cargo upgrade (-h | --help)
    cargo upgrade (-V | --version)

Options:
    --all                   Upgrade all packages in the workspace.
    --manifest-path PATH    Path to the manifest to upgrade.
    --allow-prerelease      Include prerelease versions when fetching from crates.io (e.g.
                            '0.6.0-alpha'). Defaults to false.
    --dry-run               Print changes to be made without making them. Defaults to false.
    -h --help               Show this help page.
    -V --version            Show version.

This command differs from `cargo update`, which updates the dependency versions recorded in the
local lock file (Cargo.lock).

If `<dependency>`(s) are provided, only the specified dependencies will be upgraded. The version to
upgrade to for each can be specified with e.g. `docopt@0.8.0` or `serde@>=0.9,<2.0`.

Dev, build, and all target dependencies will also be upgraded. Only dependencies from crates.io are
supported. Git/path dependencies will be ignored.

All packages in the workspace will be upgraded if the `--all` flag is supplied. The `--all` flag may
be supplied in the presence of a virtual manifest.
";

/// Docopts input args.
#[derive(Debug, Deserialize)]
struct Args {
    /// `<dependency>...`
    arg_dependency: Vec<String>,
    /// `--manifest-path PATH`
    flag_manifest_path: Option<String>,
    /// `--all`
    flag_all: bool,
    /// `--allow-prerelease`
    flag_allow_prerelease: bool,
    /// `--dry-run`
    flag_dry_run: bool,
    /// `--version`
    flag_version: bool,
}

/// A collection of manifests.
struct Manifests(Vec<(LocalManifest, cargo_metadata::Package)>);

impl Manifests {
    /// Get all manifests in the workspace.
    fn get_all(manifest_path: &Option<String>) -> Result<Self> {
        let manifest_path = manifest_path.clone().map(PathBuf::from);

        cargo_metadata::metadata_deps(manifest_path.as_ref().map(Path::new), true)
            .chain_err(|| "Failed to get workspace metadata")?
            .packages
            .into_iter()
            .map(|package| {
                Ok((
                    LocalManifest::try_new(Path::new(&package.manifest_path))?,
                    package,
                ))
            })
            .collect::<Result<Vec<_>>>()
            .map(Manifests)
    }

    /// Get the manifest specified by the manifest path. Try to make an educated guess if no path is
    /// provided.
    fn get_local_one(manifest_path: &Option<String>) -> Result<Self> {
        let manifest_path = manifest_path.clone().map(PathBuf::from);
        let resolved_manifest_path: String = find(&manifest_path)?.to_string_lossy().into();

        let manifest = LocalManifest::find(&manifest_path)?;

        let packages = cargo_metadata::metadata_deps(manifest_path.as_ref().map(Path::new), true)
            .chain_err(|| "Invalid manifest")?
            .packages;
        let package = packages
            .iter()
            .find(|p| p.manifest_path == resolved_manifest_path)
            // If we have successfully got metadata, but our manifest path does not correspond to a
            // package, we must have been called against a virtual manifest.
            .chain_err(|| "Found virtual manifest, but this command requires running against an \
                           actual package in this workspace. Try adding `--all`.")?;

        Ok(Manifests(vec![(manifest, package.to_owned())]))
    }

    /// Get the the combined set of dependencies to upgrade. If the user has specified
    /// per-dependency desired versions, extract those here.
    fn get_dependencies(&self, only_update: Vec<String>) -> Result<DesiredUpgrades> {
        /// Helper function to check whether a `cargo_metadata::Dependency` is a version dependency.
        fn is_version_dep(dependency: &cargo_metadata::Dependency) -> bool {
            match dependency.source {
                // This is the criterion cargo uses (in `SourceId::from_url`) to decide whether a
                // dependency has the 'registry' kind.
                Some(ref s) => s.splitn(2, '+').next() == Some("registry"),
                _ => false,
            }
        }

        Ok(DesiredUpgrades(if only_update.is_empty() {
            // User hasn't asked for any specific dependencies to be upgraded, so upgrade all the
            // dependencies.
            self.0
                .iter()
                .flat_map(|&(_, ref package)| package.dependencies.clone())
                .filter(is_version_dep)
                .map(|dependency| (dependency.name, None))
                .collect()
        } else {
            only_update
                .into_iter()
                .map(|name| {
                    if let Some(dependency) = CrateName::new(&name.clone()).parse_as_version()? {
                        Ok((
                            dependency.name.clone(),
                            dependency.version().map(String::from),
                        ))
                    } else {
                        Ok((name, None))
                    }
                })
                .collect::<Result<_>>()?
        }))
    }

    /// Upgrade the manifests on disk following the previously-determined upgrade schema.
    fn upgrade(self, upgraded_deps: &ActualUpgrades, dry_run: bool) -> Result<()> {
        if dry_run {
            let bufwtr = BufferWriter::stdout(ColorChoice::Always);
            let mut buffer = bufwtr.buffer();
            buffer
                .set_color(ColorSpec::new().set_fg(Some(Color::Cyan)).set_bold(true))
                .chain_err(|| "Failed to set output colour")?;
            write!(&mut buffer, "Starting dry run. ")
                .chain_err(|| "Failed to write dry run message")?;
            buffer
                .set_color(&ColorSpec::new())
                .chain_err(|| "Failed to clear output colour")?;
            writeln!(&mut buffer, "Changes will not be saved.")
                .chain_err(|| "Failed to write dry run message")?;
            bufwtr
                .print(&buffer)
                .chain_err(|| "Failed to print dry run message")?;
        }

        for (mut manifest, _) in self.0 {
            for (name, version) in &upgraded_deps.0 {
                manifest.upgrade(&Dependency::new(name).set_version(version), dry_run)?;
            }
        }

        Ok(())
    }
}

/// The set of dependencies to be upgraded, alongside desired versions, if specified by the user.
struct DesiredUpgrades(HashMap<String, Option<String>>);

/// The complete specification of the upgrades that will be performed. Map of the dependency names
/// to the new versions.
struct ActualUpgrades(HashMap<String, String>);

impl DesiredUpgrades {
    /// Transform the dependencies into their upgraded forms. If a version is specified, all
    /// dependencies will get that version.
    fn get_upgraded(self, allow_prerelease: bool) -> Result<ActualUpgrades> {
        self.0
            .into_iter()
            .map(|(name, version)| {
                if let Some(v) = version {
                    Ok((name, v))
                } else {
                    get_latest_dependency(&name, allow_prerelease)
                        .map(|new_dep| {
                            (
                                name,
                                new_dep
                                    .version()
                                    .expect("Invalid dependency type")
                                    .to_string(),
                            )
                        })
                        .chain_err(|| "Failed to get new version")
                }
            })
            .collect::<Result<_>>()
            .map(ActualUpgrades)
    }
}

/// Main processing function. Allows us to return a `Result` so that `main` can print pretty error
/// messages.
fn process(args: Args) -> Result<()> {
    let Args {
        arg_dependency,
        flag_manifest_path,
        flag_all,
        flag_allow_prerelease,
        flag_dry_run,
        ..
    } = args;

    let manifests = if flag_all {
        Manifests::get_all(&flag_manifest_path)
    } else {
        Manifests::get_local_one(&flag_manifest_path)
    }?;

    let existing_dependencies = manifests.get_dependencies(arg_dependency)?;

    let upgraded_dependencies = existing_dependencies.get_upgraded(flag_allow_prerelease)?;

    manifests.upgrade(&upgraded_dependencies, flag_dry_run)
}

fn main() {
    let args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.deserialize::<Args>())
        .unwrap_or_else(|err| err.exit());

    if args.flag_version {
        println!("cargo-upgrade version {}", env!("CARGO_PKG_VERSION"));
        process::exit(0);
    }

    if let Err(err) = process(args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<commit_msg>Pass `--no-deps` flag to cargo metadata<commit_after>//! `cargo upgrade`
#![warn(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
        trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
        unused_qualifications)]

extern crate cargo_metadata;
extern crate docopt;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate serde_derive;
extern crate toml_edit;

use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::io::Write;
use std::process;

extern crate cargo_edit;
use cargo_edit::{find, get_latest_dependency, CrateName, Dependency, LocalManifest};

extern crate termcolor;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};

mod errors {
    error_chain!{
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
            CargoMetadata(::cargo_metadata::Error, ::cargo_metadata::ErrorKind);
        }
    }
}
use errors::*;

static USAGE: &'static str = r"
Upgrade dependencies as specified in the local manifest file (i.e. Cargo.toml).

Usage:
    cargo upgrade [options] [<dependency>]...
    cargo upgrade (-h | --help)
    cargo upgrade (-V | --version)

Options:
    --all                   Upgrade all packages in the workspace.
    --manifest-path PATH    Path to the manifest to upgrade.
    --allow-prerelease      Include prerelease versions when fetching from crates.io (e.g.
                            '0.6.0-alpha'). Defaults to false.
    --dry-run               Print changes to be made without making them. Defaults to false.
    -h --help               Show this help page.
    -V --version            Show version.

This command differs from `cargo update`, which updates the dependency versions recorded in the
local lock file (Cargo.lock).

If `<dependency>`(s) are provided, only the specified dependencies will be upgraded. The version to
upgrade to for each can be specified with e.g. `docopt@0.8.0` or `serde@>=0.9,<2.0`.

Dev, build, and all target dependencies will also be upgraded. Only dependencies from crates.io are
supported. Git/path dependencies will be ignored.

All packages in the workspace will be upgraded if the `--all` flag is supplied. The `--all` flag may
be supplied in the presence of a virtual manifest.
";

/// Docopts input args.
#[derive(Debug, Deserialize)]
struct Args {
    /// `<dependency>...`
    arg_dependency: Vec<String>,
    /// `--manifest-path PATH`
    flag_manifest_path: Option<String>,
    /// `--all`
    flag_all: bool,
    /// `--allow-prerelease`
    flag_allow_prerelease: bool,
    /// `--dry-run`
    flag_dry_run: bool,
    /// `--version`
    flag_version: bool,
}

/// A collection of manifests.
struct Manifests(Vec<(LocalManifest, cargo_metadata::Package)>);

impl Manifests {
    /// Get all manifests in the workspace.
    fn get_all(manifest_path: &Option<String>) -> Result<Self> {
        let manifest_path = manifest_path.clone().map(PathBuf::from);

        cargo_metadata::metadata(manifest_path.as_ref().map(Path::new))
            .chain_err(|| "Failed to get workspace metadata")?
            .packages
            .into_iter()
            .map(|package| {
                Ok((
                    LocalManifest::try_new(Path::new(&package.manifest_path))?,
                    package,
                ))
            })
            .collect::<Result<Vec<_>>>()
            .map(Manifests)
    }

    /// Get the manifest specified by the manifest path. Try to make an educated guess if no path is
    /// provided.
    fn get_local_one(manifest_path: &Option<String>) -> Result<Self> {
        let manifest_path = manifest_path.clone().map(PathBuf::from);
        let resolved_manifest_path: String = find(&manifest_path)?.to_string_lossy().into();

        let manifest = LocalManifest::find(&manifest_path)?;

        let packages = cargo_metadata::metadata(manifest_path.as_ref().map(Path::new))
            .chain_err(|| "Invalid manifest")?
            .packages;
        let package = packages
            .iter()
            .find(|p| p.manifest_path == resolved_manifest_path)
            // If we have successfully got metadata, but our manifest path does not correspond to a
            // package, we must have been called against a virtual manifest.
            .chain_err(|| "Found virtual manifest, but this command requires running against an \
                           actual package in this workspace. Try adding `--all`.")?;

        Ok(Manifests(vec![(manifest, package.to_owned())]))
    }

    /// Get the the combined set of dependencies to upgrade. If the user has specified
    /// per-dependency desired versions, extract those here.
    fn get_dependencies(&self, only_update: Vec<String>) -> Result<DesiredUpgrades> {
        /// Helper function to check whether a `cargo_metadata::Dependency` is a version dependency.
        fn is_version_dep(dependency: &cargo_metadata::Dependency) -> bool {
            match dependency.source {
                // This is the criterion cargo uses (in `SourceId::from_url`) to decide whether a
                // dependency has the 'registry' kind.
                Some(ref s) => s.splitn(2, '+').next() == Some("registry"),
                _ => false,
            }
        }

        Ok(DesiredUpgrades(if only_update.is_empty() {
            // User hasn't asked for any specific dependencies to be upgraded, so upgrade all the
            // dependencies.
            self.0
                .iter()
                .flat_map(|&(_, ref package)| package.dependencies.clone())
                .filter(is_version_dep)
                .map(|dependency| (dependency.name, None))
                .collect()
        } else {
            only_update
                .into_iter()
                .map(|name| {
                    if let Some(dependency) = CrateName::new(&name.clone()).parse_as_version()? {
                        Ok((
                            dependency.name.clone(),
                            dependency.version().map(String::from),
                        ))
                    } else {
                        Ok((name, None))
                    }
                })
                .collect::<Result<_>>()?
        }))
    }

    /// Upgrade the manifests on disk following the previously-determined upgrade schema.
    fn upgrade(self, upgraded_deps: &ActualUpgrades, dry_run: bool) -> Result<()> {
        if dry_run {
            let bufwtr = BufferWriter::stdout(ColorChoice::Always);
            let mut buffer = bufwtr.buffer();
            buffer
                .set_color(ColorSpec::new().set_fg(Some(Color::Cyan)).set_bold(true))
                .chain_err(|| "Failed to set output colour")?;
            write!(&mut buffer, "Starting dry run. ")
                .chain_err(|| "Failed to write dry run message")?;
            buffer
                .set_color(&ColorSpec::new())
                .chain_err(|| "Failed to clear output colour")?;
            writeln!(&mut buffer, "Changes will not be saved.")
                .chain_err(|| "Failed to write dry run message")?;
            bufwtr
                .print(&buffer)
                .chain_err(|| "Failed to print dry run message")?;
        }

        for (mut manifest, _) in self.0 {
            for (name, version) in &upgraded_deps.0 {
                manifest.upgrade(&Dependency::new(name).set_version(version), dry_run)?;
            }
        }

        Ok(())
    }
}

/// The set of dependencies to be upgraded, alongside desired versions, if specified by the user.
struct DesiredUpgrades(HashMap<String, Option<String>>);

/// The complete specification of the upgrades that will be performed. Map of the dependency names
/// to the new versions.
struct ActualUpgrades(HashMap<String, String>);

impl DesiredUpgrades {
    /// Transform the dependencies into their upgraded forms. If a version is specified, all
    /// dependencies will get that version.
    fn get_upgraded(self, allow_prerelease: bool) -> Result<ActualUpgrades> {
        self.0
            .into_iter()
            .map(|(name, version)| {
                if let Some(v) = version {
                    Ok((name, v))
                } else {
                    get_latest_dependency(&name, allow_prerelease)
                        .map(|new_dep| {
                            (
                                name,
                                new_dep
                                    .version()
                                    .expect("Invalid dependency type")
                                    .to_string(),
                            )
                        })
                        .chain_err(|| "Failed to get new version")
                }
            })
            .collect::<Result<_>>()
            .map(ActualUpgrades)
    }
}

/// Main processing function. Allows us to return a `Result` so that `main` can print pretty error
/// messages.
fn process(args: Args) -> Result<()> {
    let Args {
        arg_dependency,
        flag_manifest_path,
        flag_all,
        flag_allow_prerelease,
        flag_dry_run,
        ..
    } = args;

    let manifests = if flag_all {
        Manifests::get_all(&flag_manifest_path)
    } else {
        Manifests::get_local_one(&flag_manifest_path)
    }?;

    let existing_dependencies = manifests.get_dependencies(arg_dependency)?;

    let upgraded_dependencies = existing_dependencies.get_upgraded(flag_allow_prerelease)?;

    manifests.upgrade(&upgraded_dependencies, flag_dry_run)
}

fn main() {
    let args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.deserialize::<Args>())
        .unwrap_or_else(|err| err.exit());

    if args.flag_version {
        println!("cargo-upgrade version {}", env!("CARGO_PKG_VERSION"));
        process::exit(0);
    }

    if let Err(err) = process(args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<|endoftext|>


<commit_before>use super::mode;
use super::util;
use std::collections::DList;
use std::collections::Deque;

#[deriving(Clone)]
#[deriving(Show)]
enum DOC {
    Nil,
    Append(Box<Doc>, Box<Doc>),
    Group(Box<Doc>),
    Nest(uint, Box<Doc>),
    Newline,
    Text(String),
}

pub type Doc = DOC;

fn fitting(xs:DList<(uint,mode::Mode,Doc)>, left:uint) -> bool {
    let mut tail = xs.clone();
    match tail.pop_front() {
        None => {
            true
        },
        Some((i, mode, ref doc)) => match doc.clone() {
            Nil => {
                fitting(tail, left)
            },
            Append(box x, box y) => {
                let mut prefix = DList::new();
                prefix.push((i, mode, x));
                prefix.push((i, mode, y));
                tail.prepend(prefix);
                fitting(tail, left)
            },
            Nest(j, box x) => {
                let mut prefix = DList::new();
                prefix.push((i + j, mode, x));
                tail.prepend(prefix);
                fitting(tail, left)
            },
            Text(str) => {
                fitting(tail, left - str.len())
            },
            Newline => {
                true
            },
            Group(box x) => {
                let mut prefix = DList::new();
                prefix.push((i, mode, x));
                tail.prepend(prefix);
                fitting(tail, left)
            },
        }
    }
}

fn best(w:uint, s:DList<String>, x:Doc) -> DList<String> {
    let mut start = DList::new();
    start.push((0u, mode::Break, x.clone()));

    let mut result = s.clone();
    let mut k = 0u;

    loop {
        match start.pop_front() {
            None => {
                break;
            },
            Some((i, mode, ref doc)) => match doc.clone() {
                Nil => {},
                Append(box x, box y) => {
                    let mut prefix = DList::new();
                    prefix.push((i, mode, x));
                    prefix.push((i, mode, y));
                    start.prepend(prefix);
                },
                Nest(j, box x) => {
                    let mut prefix = DList::new();
                    prefix.push((i + j, mode, x));
                    start.prepend(prefix);
                },
                Text(str) => {
                    let mut prefix = DList::new();
                    prefix.push(str.clone());
                    result.prepend(prefix);
                    k += str.len();
                },
                Newline => {
                    let mut prefix = DList::new();
                    prefix.push(util::string::nl_spaces(i));
                    result.prepend(prefix);
                    k = i;
                },
                Group(ref x) => match mode {
                    mode::Flat => {
                        let mut prefix = DList::new();
                        prefix.push((i, mode::Flat, *x.clone()));
                        start.prepend(prefix);
                    },
                    mode::Break => {
                        let mut ys = start.clone();
                        let mut flat_prefix = DList::new();
                        flat_prefix.push((i, mode::Flat, *x.clone()));
                        ys.prepend(flat_prefix);
                        if fitting(ys, w - k) {
                            let mut prefix = DList::new();
                            prefix.push((i, mode::Flat, *x.clone()));
                            start.prepend(prefix);
                        } else {
                            let mut prefix = DList::new();
                            prefix.push((i, mode::Break, *x.clone()));
                            start.prepend(prefix);
                        }
                    }
                }
            }
        }
    }

    result
}

impl Doc {

    pub fn nil() -> Doc {
        Nil
    }

    pub fn append(self, e:Doc) -> Doc {
        match self {
            Nil => e,
            x => match e {
                Nil => x,
                y => Append(box x, box y)
            }
        }
    }

    pub fn nest(self, i:uint) -> Doc {
        Nest(i, box self)
    }

    pub fn text<S:Str>(s:S) -> Doc {
        Text(String::from_str(s.as_slice()))
    }

    pub fn newline() -> Doc {
        Newline
    }

    pub fn group(self) -> Doc {
        Group(box self)
    }

    pub fn concat(ds:&[Doc]) -> Doc {
        ds.iter().fold(Nil, |a, b| a.append(b.clone()))
    }

    pub fn as_string<T:ToString>(t:T) -> Doc {
        Doc::text(t.to_string())
    }

    pub fn render(self, w:uint) -> String {
        let strs = best(w, DList::new(), self);

        let mut result = String::new();
        for str in strs.iter().rev() {
            result.push_str(str.as_slice());
        }
        result
    }
}
<commit_msg>Remove recursion from fitting; fix incorrect implementation<commit_after>use super::mode;
use super::util;
use std::collections::DList;
use std::collections::Deque;

#[deriving(Clone)]
#[deriving(Show)]
enum DOC {
    Nil,
    Append(Box<Doc>, Box<Doc>),
    Group(Box<Doc>),
    Nest(uint, Box<Doc>),
    Newline,
    Text(String),
}

pub type Doc = DOC;

fn fitting(xs:&mut DList<(uint,mode::Mode,Doc)>, initial_left:int) -> bool {
    let mut fits = true;

    let mut left = initial_left;

    loop {
        if left < 0 {
            fits = false;
            break;
        }

        match xs.pop_front() {
            None => {
                break;
            },
            Some((i, mode, ref doc)) => match doc.clone() {
                Nil => {},
                Append(box x, box y) => {
                    let mut prefix = DList::new();
                    prefix.push((i, mode, x));
                    prefix.push((i, mode, y));
                    xs.prepend(prefix);
                },
                Nest(j, box x) => {
                    let mut prefix = DList::new();
                    prefix.push((i + j, mode, x));
                    xs.prepend(prefix);
                },
                Text(str) => {
                    left -= str.len() as int;
                },
                Newline => {
                    fits = true;
                },
                Group(box x) => {
                    let mut prefix = DList::new();
                    prefix.push((i, mode, x));
                    xs.prepend(prefix);
                },
            }
        }
    }

    fits
}

fn best(w:uint, s:DList<String>, x:Doc) -> DList<String> {
    let mut start = DList::new();
    start.push((0u, mode::Break, x.clone()));

    let mut result = s.clone();
    let mut k = 0u;

    loop {
        match start.pop_front() {
            None => {
                break;
            },
            Some((i, mode, ref doc)) => match doc.clone() {
                Nil => {},
                Append(box x, box y) => {
                    let mut prefix = DList::new();
                    prefix.push((i, mode, x));
                    prefix.push((i, mode, y));
                    start.prepend(prefix);
                },
                Nest(j, box x) => {
                    let mut prefix = DList::new();
                    prefix.push((i + j, mode, x));
                    start.prepend(prefix);
                },
                Text(str) => {
                    let mut prefix = DList::new();
                    prefix.push(str.clone());
                    result.prepend(prefix);
                    k += str.len();
                },
                Newline => {
                    let mut prefix = DList::new();
                    prefix.push(util::string::nl_spaces(i));
                    result.prepend(prefix);
                    k = i;
                },
                Group(ref x) => match mode {
                    mode::Flat => {
                        let mut prefix = DList::new();
                        prefix.push((i, mode::Flat, *x.clone()));
                        start.prepend(prefix);
                    },
                    mode::Break => {
                        let mut ys = start.clone();
                        let mut flat_prefix = DList::new();
                        flat_prefix.push((i, mode::Flat, *x.clone()));
                        ys.prepend(flat_prefix);
                        if fitting(&mut ys, w as int - k as int) {
                            let mut prefix = DList::new();
                            prefix.push((i, mode::Flat, *x.clone()));
                            start.prepend(prefix);
                        } else {
                            let mut prefix = DList::new();
                            prefix.push((i, mode::Break, *x.clone()));
                            start.prepend(prefix);
                        }
                    }
                }
            }
        }
    }

    result
}

impl Doc {

    pub fn nil() -> Doc {
        Nil
    }

    pub fn append(self, e:Doc) -> Doc {
        match self {
            Nil => e,
            x => match e {
                Nil => x,
                y => Append(box x, box y)
            }
        }
    }

    pub fn nest(self, i:uint) -> Doc {
        Nest(i, box self)
    }

    pub fn text<S:Str>(s:S) -> Doc {
        Text(String::from_str(s.as_slice()))
    }

    pub fn newline() -> Doc {
        Newline
    }

    pub fn group(self) -> Doc {
        Group(box self)
    }

    pub fn concat(ds:&[Doc]) -> Doc {
        ds.iter().fold(Nil, |a, b| a.append(b.clone()))
    }

    pub fn as_string<T:ToString>(t:T) -> Doc {
        Doc::text(t.to_string())
    }

    pub fn render(self, w:uint) -> String {
        let strs = best(w, DList::new(), self);

        let mut result = String::new();
        for str in strs.iter().rev() {
            result.push_str(str.as_slice());
        }
        result
    }
}
<|endoftext|>


<commit_before>use super::mode;
use super::util;
use std::collections::DList;
use std::collections::Deque;

#[deriving(Clone)]
#[deriving(Show)]
enum DOC {
    Nil,
    Append(Box<Doc>, Box<Doc>),
    Group(Box<Doc>),
    Nest(uint, Box<Doc>),
    Newline,
    Text(String),
}

pub type Doc = DOC;

fn fitting(mut cmds: DList<(uint,mode::Mode,Doc)>, mut rem:int) -> bool {
    let mut fits = true;

    loop {
        if rem < 0 {
            fits = false;
            break;
        }
        match cmds.pop_front() {
            None => {
                break;
            },
            Some((i, mode, ref doc)) => match doc.clone() {
                Nil => {},
                Append(box x, box y) => {
                    let mut prefix = DList::new();
                    prefix.push((i, mode, x));
                    prefix.push((i, mode, y));
                    cmds.prepend(prefix);
                },
                Nest(j, box x) => {
                    let mut prefix = DList::new();
                    prefix.push((i + j, mode, x));
                    cmds.prepend(prefix);
                },
                Text(str) => {
                    rem -= str.len() as int;
                },
                Newline => {
                    fits = true;
                },
                Group(box x) => {
                    let mut prefix = DList::new();
                    prefix.push((i, mode, x));
                    cmds.prepend(prefix);
                },
            }
        }
    }

    fits
}

fn best(width:uint, mut buf:DList<String>, x:Doc) -> DList<String> {
    let mut pos: uint = 0;
    let mut cmds: DList<(uint,mode::Mode,Doc)> = DList::new();

    cmds.push((0, mode::Break, x));

    loop {
        match cmds.pop_front() {
            None => {
                break;
            },
            Some((i, mode, ref doc)) => match doc.clone() {
                Nil => {},
                Append(box x, box y) => {
                    let mut prefix = DList::new();
                    prefix.push((i, mode, x));
                    prefix.push((i, mode, y));
                    cmds.prepend(prefix);
                },
                Nest(j, box x) => {
                    let mut prefix = DList::new();
                    prefix.push((i + j, mode, x));
                    cmds.prepend(prefix);
                },
                Text(str) => {
                    let mut prefix = DList::new();
                    prefix.push(str.clone());
                    buf.prepend(prefix);
                    pos += str.len();
                },
                Newline => {
                    let mut prefix = DList::new();
                    prefix.push(util::string::nl_spaces(i));
                    buf.prepend(prefix);
                    pos = i;
                },
                Group(box x) => match mode {
                    mode::Flat => {
                        let mut prefix = DList::new();
                        prefix.push((i, mode::Flat, x));
                        cmds.prepend(prefix);
                    },
                    mode::Break => {
                        let mut cmds_dup = cmds.clone();
                        let mut flat_prefix = DList::new();
                        flat_prefix.push((i, mode::Flat, x.clone()));
                        cmds_dup.prepend(flat_prefix);
                        if fitting(cmds_dup, width as int - pos as int) {
                            let mut prefix = DList::new();
                            prefix.push((i, mode::Flat, x));
                            cmds.prepend(prefix);
                        } else {
                            let mut prefix = DList::new();
                            prefix.push((i, mode::Break, x));
                            cmds.prepend(prefix);
                        }
                    }
                }
            }
        }
    }

    buf
}

impl Doc {

    pub fn nil() -> Doc {
        Nil
    }

    pub fn append(self, e:Doc) -> Doc {
        match self {
            Nil => e,
            x => match e {
                Nil => x,
                y => Append(box x, box y)
            }
        }
    }

    pub fn nest(self, i:uint) -> Doc {
        Nest(i, box self)
    }

    pub fn text<S:Str>(s:S) -> Doc {
        Text(String::from_str(s.as_slice()))
    }

    pub fn newline() -> Doc {
        Newline
    }

    pub fn group(self) -> Doc {
        Group(box self)
    }

    pub fn concat(ds:&[Doc]) -> Doc {
        ds.iter().fold(Nil, |a, b| a.append(b.clone()))
    }

    pub fn as_string<T:ToString>(t:T) -> Doc {
        Doc::text(t.to_string())
    }

    pub fn render(self, w:uint) -> String {
        let strs = best(w, DList::new(), self);

        let mut result = String::new();
        for str in strs.iter().rev() {
            result.push_str(str.as_slice());
        }
        result
    }
}
<commit_msg>Inline 'best' strs<commit_after>use super::mode;
use super::util;
use std::collections::DList;
use std::collections::Deque;

#[deriving(Clone)]
#[deriving(Show)]
enum DOC {
    Nil,
    Append(Box<Doc>, Box<Doc>),
    Group(Box<Doc>),
    Nest(uint, Box<Doc>),
    Newline,
    Text(String),
}

pub type Doc = DOC;

fn fitting(mut cmds: DList<(uint,mode::Mode,Doc)>, mut rem:int) -> bool {
    let mut fits = true;

    loop {
        if rem < 0 {
            fits = false;
            break;
        }
        match cmds.pop_front() {
            None => {
                break;
            },
            Some((i, mode, ref doc)) => match doc.clone() {
                Nil => {},
                Append(box x, box y) => {
                    let mut prefix = DList::new();
                    prefix.push((i, mode, x));
                    prefix.push((i, mode, y));
                    cmds.prepend(prefix);
                },
                Nest(j, box x) => {
                    let mut prefix = DList::new();
                    prefix.push((i + j, mode, x));
                    cmds.prepend(prefix);
                },
                Text(str) => {
                    rem -= str.len() as int;
                },
                Newline => {
                    fits = true;
                },
                Group(box x) => {
                    let mut prefix = DList::new();
                    prefix.push((i, mode, x));
                    cmds.prepend(prefix);
                },
            }
        }
    }

    fits
}

fn best(width:uint, mut buf:DList<String>, x:Doc) -> DList<String> {
    let mut pos: uint = 0;
    let mut cmds: DList<(uint,mode::Mode,Doc)> = DList::new();

    cmds.push((0, mode::Break, x));

    loop {
        match cmds.pop_front() {
            None => {
                break;
            },
            Some((i, mode, ref doc)) => match doc.clone() {
                Nil => {},
                Append(box x, box y) => {
                    let mut prefix = DList::new();
                    prefix.push((i, mode, x));
                    prefix.push((i, mode, y));
                    cmds.prepend(prefix);
                },
                Nest(j, box x) => {
                    let mut prefix = DList::new();
                    prefix.push((i + j, mode, x));
                    cmds.prepend(prefix);
                },
                Text(str) => {
                    let mut prefix = DList::new();
                    prefix.push(str.clone());
                    buf.prepend(prefix);
                    pos += str.len();
                },
                Newline => {
                    let mut prefix = DList::new();
                    prefix.push(util::string::nl_spaces(i));
                    buf.prepend(prefix);
                    pos = i;
                },
                Group(box x) => match mode {
                    mode::Flat => {
                        let mut prefix = DList::new();
                        prefix.push((i, mode::Flat, x));
                        cmds.prepend(prefix);
                    },
                    mode::Break => {
                        let mut cmds_dup = cmds.clone();
                        let mut flat_prefix = DList::new();
                        flat_prefix.push((i, mode::Flat, x.clone()));
                        cmds_dup.prepend(flat_prefix);
                        if fitting(cmds_dup, width as int - pos as int) {
                            let mut prefix = DList::new();
                            prefix.push((i, mode::Flat, x));
                            cmds.prepend(prefix);
                        } else {
                            let mut prefix = DList::new();
                            prefix.push((i, mode::Break, x));
                            cmds.prepend(prefix);
                        }
                    }
                }
            }
        }
    }

    buf
}

impl Doc {

    pub fn nil() -> Doc {
        Nil
    }

    pub fn append(self, e:Doc) -> Doc {
        match self {
            Nil => e,
            x => match e {
                Nil => x,
                y => Append(box x, box y)
            }
        }
    }

    pub fn nest(self, i:uint) -> Doc {
        Nest(i, box self)
    }

    pub fn text<S:Str>(s:S) -> Doc {
        Text(String::from_str(s.as_slice()))
    }

    pub fn newline() -> Doc {
        Newline
    }

    pub fn group(self) -> Doc {
        Group(box self)
    }

    pub fn concat(ds:&[Doc]) -> Doc {
        ds.iter().fold(Nil, |a, b| a.append(b.clone()))
    }

    pub fn as_string<T:ToString>(t:T) -> Doc {
        Doc::text(t.to_string())
    }

    pub fn render(self, w:uint) -> String {
        let mut result = String::new();
        for str in best(w, DList::new(), self).iter().rev() {
            result.push_str(str.as_slice());
        }
        result
    }

}
<|endoftext|>


<commit_before>mod exponent;
mod mantissa;

use core::{mem, ptr};

use self::exponent::*;
use self::mantissa::*;
use common;
use d2s;
use d2s::*;
use f2s::*;

#[cfg(feature = "no-panic")]
use no_panic::no_panic;

/// Print f64 to the given buffer and return number of bytes written.
///
/// At most 24 bytes will be written.
///
/// ## Special cases
///
/// This function **does not** check for NaN or infinity. If the input
/// number is not a finite float, the printed representation will be some
/// correctly formatted but unspecified numerical value.
///
/// Please check [`is_finite`] yourself before calling this function, or
/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself.
///
/// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_finite
/// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_nan
/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_infinite
///
/// ## Safety
///
/// The `result` pointer argument must point to sufficiently many writable bytes
/// to hold Ryū's representation of `f`.
///
/// ## Example
///
/// ```edition2018
/// use std::mem::MaybeUninit;
///
/// let f = 1.234f64;
///
/// unsafe {
///     let mut buffer = [MaybeUninit::<u8>::uninit(); 24];
///     let len = ryu::raw::format64(f, buffer.as_mut_ptr() as *mut u8);
///     let slice = std::slice::from_raw_parts(buffer.as_ptr() as *const u8, len);
///     let print = std::str::from_utf8_unchecked(slice);
///     assert_eq!(print, "1.234");
/// }
/// ```
#[cfg_attr(must_use_return, must_use)]
#[cfg_attr(feature = "no-panic", no_panic)]
pub unsafe fn format64(f: f64, result: *mut u8) -> usize {
    let bits = mem::transmute::<f64, u64>(f);
    let sign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0;
    let ieee_mantissa = bits & ((1u64 << DOUBLE_MANTISSA_BITS) - 1);
    let ieee_exponent =
        (bits >> DOUBLE_MANTISSA_BITS) as u32 & ((1u32 << DOUBLE_EXPONENT_BITS) - 1);

    let mut index = 0isize;
    if sign {
        *result = b'-';
        index += 1;
    }

    if ieee_exponent == 0 && ieee_mantissa == 0 {
        ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3);
        return sign as usize + 3;
    }

    let v = d2d(ieee_mantissa, ieee_exponent);

    let length = d2s::decimal_length17(v.mantissa) as isize;
    let k = v.exponent as isize;
    let kk = length + k; // 10^(kk-1) <= v < 10^kk
    debug_assert!(k >= -324);

    if 0 <= k && kk <= 16 {
        // 1234e7 -> 12340000000.0
        write_mantissa_long(v.mantissa, result.offset(index + length));
        for i in length..kk {
            *result.offset(index + i) = b'0';
        }
        *result.offset(index + kk) = b'.';
        *result.offset(index + kk + 1) = b'0';
        index as usize + kk as usize + 2
    } else if 0 < kk && kk <= 16 {
        // 1234e-2 -> 12.34
        write_mantissa_long(v.mantissa, result.offset(index + length + 1));
        ptr::copy(result.offset(index + 1), result.offset(index), kk as usize);
        *result.offset(index + kk) = b'.';
        index as usize + length as usize + 1
    } else if -5 < kk && kk <= 0 {
        // 1234e-6 -> 0.001234
        *result.offset(index) = b'0';
        *result.offset(index + 1) = b'.';
        let offset = 2 - kk;
        for i in 2..offset {
            *result.offset(index + i) = b'0';
        }
        write_mantissa_long(v.mantissa, result.offset(index + length + offset));
        index as usize + length as usize + offset as usize
    } else if length == 1 {
        // 1e30
        *result.offset(index) = b'0' + v.mantissa as u8;
        *result.offset(index + 1) = b'e';
        index as usize + 2 + write_exponent3(kk - 1, result.offset(index + 2))
    } else {
        // 1234e30 -> 1.234e33
        write_mantissa_long(v.mantissa, result.offset(index + length + 1));
        *result.offset(index) = *result.offset(index + 1);
        *result.offset(index + 1) = b'.';
        *result.offset(index + length + 1) = b'e';
        index as usize
            + length as usize
            + 2
            + write_exponent3(kk - 1, result.offset(index + length + 2))
    }
}

/// Print f32 to the given buffer and return number of bytes written.
///
/// At most 16 bytes will be written.
///
/// ## Special cases
///
/// This function **does not** check for NaN or infinity. If the input
/// number is not a finite float, the printed representation will be some
/// correctly formatted but unspecified numerical value.
///
/// Please check [`is_finite`] yourself before calling this function, or
/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself.
///
/// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_finite
/// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_nan
/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_infinite
///
/// ## Safety
///
/// The `result` pointer argument must point to sufficiently many writable bytes
/// to hold Ryū's representation of `f`.
///
/// ## Example
///
/// ```edition2018
/// use std::mem::MaybeUninit;
///
/// let f = 1.234f32;
///
/// unsafe {
///     let mut buffer = [MaybeUninit::<u8>::uninit(); 16];
///     let len = ryu::raw::format32(f, buffer.as_mut_ptr() as *mut u8);
///     let slice = std::slice::from_raw_parts(buffer.as_ptr() as *const u8, len);
///     let print = std::str::from_utf8_unchecked(slice);
///     assert_eq!(print, "1.234");
/// }
/// ```
#[cfg_attr(must_use_return, must_use)]
#[cfg_attr(feature = "no-panic", no_panic)]
pub unsafe fn format32(f: f32, result: *mut u8) -> usize {
    let bits = mem::transmute::<f32, u32>(f);
    let sign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0;
    let ieee_mantissa = bits & ((1u32 << FLOAT_MANTISSA_BITS) - 1);
    let ieee_exponent =
        ((bits >> FLOAT_MANTISSA_BITS) & ((1u32 << FLOAT_EXPONENT_BITS) - 1)) as u32;

    let mut index = 0isize;
    if sign {
        *result = b'-';
        index += 1;
    }

    if ieee_exponent == 0 && ieee_mantissa == 0 {
        ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3);
        return sign as usize + 3;
    }

    let v = f2d(ieee_mantissa, ieee_exponent);

    let length = common::decimal_length9(v.mantissa) as isize;
    let k = v.exponent as isize;
    let kk = length + k; // 10^(kk-1) <= v < 10^kk
    debug_assert!(k >= -45);

    if 0 <= k && kk <= 13 {
        // 1234e7 -> 12340000000.0
        write_mantissa(v.mantissa, result.offset(index + length));
        for i in length..kk {
            *result.offset(index + i) = b'0';
        }
        *result.offset(index + kk) = b'.';
        *result.offset(index + kk + 1) = b'0';
        index as usize + kk as usize + 2
    } else if 0 < kk && kk <= 13 {
        // 1234e-2 -> 12.34
        write_mantissa(v.mantissa, result.offset(index + length + 1));
        ptr::copy(result.offset(index + 1), result.offset(index), kk as usize);
        *result.offset(index + kk) = b'.';
        index as usize + length as usize + 1
    } else if -6 < kk && kk <= 0 {
        // 1234e-6 -> 0.001234
        *result.offset(index) = b'0';
        *result.offset(index + 1) = b'.';
        let offset = 2 - kk;
        for i in 2..offset {
            *result.offset(index + i) = b'0';
        }
        write_mantissa(v.mantissa, result.offset(index + length + offset));
        index as usize + length as usize + offset as usize
    } else if length == 1 {
        // 1e30
        *result.offset(index) = b'0' + v.mantissa as u8;
        *result.offset(index + 1) = b'e';
        index as usize + 2 + write_exponent2(kk - 1, result.offset(index + 2))
    } else {
        // 1234e30 -> 1.234e33
        write_mantissa(v.mantissa, result.offset(index + length + 1));
        *result.offset(index) = *result.offset(index + 1);
        *result.offset(index + 1) = b'.';
        *result.offset(index + length + 1) = b'e';
        index as usize
            + length as usize
            + 2
            + write_exponent2(kk - 1, result.offset(index + length + 2))
    }
}
<commit_msg>Reduce density of some example code<commit_after>mod exponent;
mod mantissa;

use core::{mem, ptr};

use self::exponent::*;
use self::mantissa::*;
use common;
use d2s;
use d2s::*;
use f2s::*;

#[cfg(feature = "no-panic")]
use no_panic::no_panic;

/// Print f64 to the given buffer and return number of bytes written.
///
/// At most 24 bytes will be written.
///
/// ## Special cases
///
/// This function **does not** check for NaN or infinity. If the input
/// number is not a finite float, the printed representation will be some
/// correctly formatted but unspecified numerical value.
///
/// Please check [`is_finite`] yourself before calling this function, or
/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself.
///
/// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_finite
/// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_nan
/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_infinite
///
/// ## Safety
///
/// The `result` pointer argument must point to sufficiently many writable bytes
/// to hold Ryū's representation of `f`.
///
/// ## Example
///
/// ```edition2018
/// use std::{mem::MaybeUninit, slice, str};
///
/// let f = 1.234f64;
///
/// unsafe {
///     let mut buffer = [MaybeUninit::<u8>::uninit(); 24];
///     let len = ryu::raw::format64(f, buffer.as_mut_ptr() as *mut u8);
///     let slice = slice::from_raw_parts(buffer.as_ptr() as *const u8, len);
///     let print = str::from_utf8_unchecked(slice);
///     assert_eq!(print, "1.234");
/// }
/// ```
#[cfg_attr(must_use_return, must_use)]
#[cfg_attr(feature = "no-panic", no_panic)]
pub unsafe fn format64(f: f64, result: *mut u8) -> usize {
    let bits = mem::transmute::<f64, u64>(f);
    let sign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0;
    let ieee_mantissa = bits & ((1u64 << DOUBLE_MANTISSA_BITS) - 1);
    let ieee_exponent =
        (bits >> DOUBLE_MANTISSA_BITS) as u32 & ((1u32 << DOUBLE_EXPONENT_BITS) - 1);

    let mut index = 0isize;
    if sign {
        *result = b'-';
        index += 1;
    }

    if ieee_exponent == 0 && ieee_mantissa == 0 {
        ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3);
        return sign as usize + 3;
    }

    let v = d2d(ieee_mantissa, ieee_exponent);

    let length = d2s::decimal_length17(v.mantissa) as isize;
    let k = v.exponent as isize;
    let kk = length + k; // 10^(kk-1) <= v < 10^kk
    debug_assert!(k >= -324);

    if 0 <= k && kk <= 16 {
        // 1234e7 -> 12340000000.0
        write_mantissa_long(v.mantissa, result.offset(index + length));
        for i in length..kk {
            *result.offset(index + i) = b'0';
        }
        *result.offset(index + kk) = b'.';
        *result.offset(index + kk + 1) = b'0';
        index as usize + kk as usize + 2
    } else if 0 < kk && kk <= 16 {
        // 1234e-2 -> 12.34
        write_mantissa_long(v.mantissa, result.offset(index + length + 1));
        ptr::copy(result.offset(index + 1), result.offset(index), kk as usize);
        *result.offset(index + kk) = b'.';
        index as usize + length as usize + 1
    } else if -5 < kk && kk <= 0 {
        // 1234e-6 -> 0.001234
        *result.offset(index) = b'0';
        *result.offset(index + 1) = b'.';
        let offset = 2 - kk;
        for i in 2..offset {
            *result.offset(index + i) = b'0';
        }
        write_mantissa_long(v.mantissa, result.offset(index + length + offset));
        index as usize + length as usize + offset as usize
    } else if length == 1 {
        // 1e30
        *result.offset(index) = b'0' + v.mantissa as u8;
        *result.offset(index + 1) = b'e';
        index as usize + 2 + write_exponent3(kk - 1, result.offset(index + 2))
    } else {
        // 1234e30 -> 1.234e33
        write_mantissa_long(v.mantissa, result.offset(index + length + 1));
        *result.offset(index) = *result.offset(index + 1);
        *result.offset(index + 1) = b'.';
        *result.offset(index + length + 1) = b'e';
        index as usize
            + length as usize
            + 2
            + write_exponent3(kk - 1, result.offset(index + length + 2))
    }
}

/// Print f32 to the given buffer and return number of bytes written.
///
/// At most 16 bytes will be written.
///
/// ## Special cases
///
/// This function **does not** check for NaN or infinity. If the input
/// number is not a finite float, the printed representation will be some
/// correctly formatted but unspecified numerical value.
///
/// Please check [`is_finite`] yourself before calling this function, or
/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself.
///
/// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_finite
/// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_nan
/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_infinite
///
/// ## Safety
///
/// The `result` pointer argument must point to sufficiently many writable bytes
/// to hold Ryū's representation of `f`.
///
/// ## Example
///
/// ```edition2018
/// use std::{mem::MaybeUninit, slice, str};
///
/// let f = 1.234f32;
///
/// unsafe {
///     let mut buffer = [MaybeUninit::<u8>::uninit(); 16];
///     let len = ryu::raw::format32(f, buffer.as_mut_ptr() as *mut u8);
///     let slice = slice::from_raw_parts(buffer.as_ptr() as *const u8, len);
///     let print = str::from_utf8_unchecked(slice);
///     assert_eq!(print, "1.234");
/// }
/// ```
#[cfg_attr(must_use_return, must_use)]
#[cfg_attr(feature = "no-panic", no_panic)]
pub unsafe fn format32(f: f32, result: *mut u8) -> usize {
    let bits = mem::transmute::<f32, u32>(f);
    let sign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0;
    let ieee_mantissa = bits & ((1u32 << FLOAT_MANTISSA_BITS) - 1);
    let ieee_exponent =
        ((bits >> FLOAT_MANTISSA_BITS) & ((1u32 << FLOAT_EXPONENT_BITS) - 1)) as u32;

    let mut index = 0isize;
    if sign {
        *result = b'-';
        index += 1;
    }

    if ieee_exponent == 0 && ieee_mantissa == 0 {
        ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3);
        return sign as usize + 3;
    }

    let v = f2d(ieee_mantissa, ieee_exponent);

    let length = common::decimal_length9(v.mantissa) as isize;
    let k = v.exponent as isize;
    let kk = length + k; // 10^(kk-1) <= v < 10^kk
    debug_assert!(k >= -45);

    if 0 <= k && kk <= 13 {
        // 1234e7 -> 12340000000.0
        write_mantissa(v.mantissa, result.offset(index + length));
        for i in length..kk {
            *result.offset(index + i) = b'0';
        }
        *result.offset(index + kk) = b'.';
        *result.offset(index + kk + 1) = b'0';
        index as usize + kk as usize + 2
    } else if 0 < kk && kk <= 13 {
        // 1234e-2 -> 12.34
        write_mantissa(v.mantissa, result.offset(index + length + 1));
        ptr::copy(result.offset(index + 1), result.offset(index), kk as usize);
        *result.offset(index + kk) = b'.';
        index as usize + length as usize + 1
    } else if -6 < kk && kk <= 0 {
        // 1234e-6 -> 0.001234
        *result.offset(index) = b'0';
        *result.offset(index + 1) = b'.';
        let offset = 2 - kk;
        for i in 2..offset {
            *result.offset(index + i) = b'0';
        }
        write_mantissa(v.mantissa, result.offset(index + length + offset));
        index as usize + length as usize + offset as usize
    } else if length == 1 {
        // 1e30
        *result.offset(index) = b'0' + v.mantissa as u8;
        *result.offset(index + 1) = b'e';
        index as usize + 2 + write_exponent2(kk - 1, result.offset(index + 2))
    } else {
        // 1234e30 -> 1.234e33
        write_mantissa(v.mantissa, result.offset(index + length + 1));
        *result.offset(index) = *result.offset(index + 1);
        *result.offset(index + 1) = b'.';
        *result.offset(index + length + 1) = b'e';
        index as usize
            + length as usize
            + 2
            + write_exponent2(kk - 1, result.offset(index + length + 2))
    }
}
<|endoftext|>


<commit_before>// (c) 2016 Productize SPRL <joost@productize.be>

// extension: .lib
// format: old-style

use std::fmt;
use std::result;
use std::str::FromStr;
use std::path::PathBuf;

// get from parent
use Result;
use str_error as err;
use util::read_file;
use parse_split_quote_aware;
use schematic;
use str_error;

#[derive(Debug,Default)]
pub struct SymbolLib {
    pub symbols:Vec<Symbol>,
}

// DEF name reference unused text_offset draw_pinnumber draw_pinname unit_count units_locked option_flag
#[derive(Debug,Clone)]
pub struct Symbol {
    pub name:String,
    pub reference:String,
    pub text_offset:f64,
    pub draw_pinnumber: bool,
    pub draw_pinname: bool,
    pub unit_count: i64,
    pub unit_locked: bool,
    pub is_power: bool,
    pub fields:Vec<Field>,
    pub draw:Vec<String>, // TODO parse draw
}
// F n “text” posx posy dimension orientation visibility hjustify vjustify/italic/bold “name”
// F0 "#PWR" 0 0 30 H I C CNN

#[derive(Debug,Clone)]
pub struct Field {
    pub i:i64,
    pub value:String,
    pub x:f64,
    pub y:f64,
    pub dimension:i64,
    pub orientation:schematic::Orientation,
    pub visible:bool,
    pub hjustify:schematic::Justify,
    pub vjustify:schematic::Justify,
    pub italic:bool,
    pub bold:bool,
    pub name:String,
}

impl SymbolLib {
    pub fn find<F>(&self, filter:F) -> Option<&Symbol>
        where F:Fn(&Symbol) -> bool
    {
        for symbol in &self.symbols {
            if filter(symbol) {
                return Some(symbol)
            }
        }
        None
    }
}

impl fmt::Display for SymbolLib {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        try!(writeln!(f, "EESchema-LIBRARY Version 2.3"));
        try!(writeln!(f, "#encoding utf-8"));
        try!(writeln!(f, "#"));
        for i in &self.symbols {
            try!(write!(f, "{}", i))
        };
        writeln!(f, "#End Library")
    }
}

impl Symbol {
    pub fn new(name:String, reference:String) -> Symbol {
        Symbol {
            name:name,
            reference:reference,
            text_offset:0.0,
            draw_pinnumber:false,
            draw_pinname:false,
            unit_count:1,
            unit_locked:false,
            is_power:false,
            fields:vec![],
            draw:vec![],
        }
    }
    pub fn set_name(&mut self, name:String) {
        if char_at(&self.name, 0) == '~' {
            self.name = format!("~{}", name)
        } else {
            self.name = name.clone()
        }
        let mut field = &mut self.fields[1];
        field.value = name
    }
}

impl fmt::Display for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        try!(writeln!(f, "# {}", &&self.fields[1].value));
        try!(writeln!(f, "#"));
        try!(writeln!(f, "DEF {} {} 0 {} {} {} {} {} {}",
                     self.name, self.reference, self.text_offset,
                     if self.draw_pinnumber { "Y" } else { "N" },
                     if self.draw_pinname { "Y" } else { "N" },
                     self.unit_count,
                     if self.unit_locked { "L" } else { "F" },
                     if self.is_power { "P" } else { "N" },
                     ));
        for field in &self.fields {
            try!(writeln!(f, "{}", field))
        };
        try!(writeln!(f, "DRAW"));
        for draw in &self.draw {
            try!(writeln!(f, "{}", draw))
        };
        try!(writeln!(f, "ENDDRAW"));
        try!(writeln!(f, "ENDDEF"));
        writeln!(f, "#")
    }
}

impl Default for Field {
    fn default() -> Field {
        Field {
            i:0,
            value:String::from(""),
            x:0.0,
            y:0.0,
            dimension:0,
            orientation:schematic::Orientation::Horizontal,
            visible:false,
            hjustify:schematic::Justify::Center,
            vjustify:schematic::Justify::Center,
            italic:false,
            bold:false,
            name:String::from(""),
        }
    }
}

impl fmt::Display for Field {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        try!(write!(f, "F{} \"{}\" {} {} {} {} {} {} {}{}{}",
               self.i, self.value, self.x, self.y, self.dimension,
               self.orientation,
               if self.visible { "V" } else { "I" },
               self.hjustify, self.vjustify,
               if self.italic { "I" } else { "N" },
               if self.bold { "I" } else { "N" },
                    ));
        if self.i > 3 {
            try!(write!(f, " \"{}\"", self.name))
        };
        Ok(())
    }
}

macro_rules! assume_line {
    ($s:expr, $exp:expr) => (
        if $s.eof() {
            return str_error("end of file reached".to_string())
        }
        if $s.here() != $exp {
            return str_error(format!("expected '{}', got '{}'", $exp, $s.here()))
        }
        $s.i += 1;
    )
}

#[derive(Debug)]
struct ParseState {
    i:usize,
    v:Vec<String>,
}

impl ParseState {
    fn new(v2:Vec<&str>) -> ParseState {
        ParseState {
            i:0,
            v:v2.iter().map(|x| String::from(*x)).collect(),
        }
    }

    fn here(&self) -> String {
        (self.v[self.i]).clone()
    }

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

    fn eof(&self) -> bool {
        self.i >= self.v.len()
    }
}

fn assume_string(e:&'static str, s:&str) -> Result<()> {
    if *e != *s {
        return str_error(format!("expecting: {}, actually: {}", e, s))
    }
    Ok(())
}

fn i64_from_string(p:&ParseState, s:&str) -> Result<i64> {
    match i64::from_str(s) {
        Ok(i) => Ok(i),
        _ => str_error(format!("int parse error in {}; line: {}", s, p.here()))
    }
}

fn f64_from_string(p:&ParseState, s:&str) -> Result<f64> {
    match f64::from_str(s) {
        Ok(i) => Ok(i),
        _ => str_error(format!("float parse error in {}; line: {}", s, p.here()))
    }
}

fn bool_from_string(s:&str, t:&'static str, f:&'static str) -> Result<bool> {
    if &s[..] == t {
        return Ok(true)
    }
    if &s[..] == f {
        return Ok(false)
    }
    str_error(format!("unknown boolean {}, expected {} or {}", s, t, f))
}

fn char_at(s:&str, p:usize) -> char {
    let v:Vec<char> = s.chars().collect();
    v[..][p]
}

fn parse_symbol(p:&mut ParseState) -> Result<Symbol> {
    p.next(); // skip line like # name
    assume_line!(p,"#");
    let s = p.here();
    let v = &parse_split_quote_aware(&s);
    if v.len() != 10 {
        return str_error(format!("unexpected elements in {}", s))
    }
    try!(assume_string("DEF", &v[0]));
    let mut s = Symbol::new(v[1].clone(), v[2].clone());
    s.text_offset = try!(f64_from_string(p, &v[4]));
    s.draw_pinnumber = try!(bool_from_string(&v[5], "Y", "N"));
    s.draw_pinname = try!(bool_from_string(&v[6], "Y", "N"));
    s.unit_count = try!(i64_from_string(p, &v[7]));
    s.unit_locked = try!(bool_from_string(&v[8], "L", "F"));
    s.is_power = try!(bool_from_string(&v[9], "P", "N"));
    // TODO fields
    // TODO draw
    p.next();
    loop {
        let s2 = p.here();
        if char_at(&s2, 0) == 'F' {
            let f = try!(parse_field(p, &s2));
            s.fields.push(f);
            p.next();
        } else {
            break;
        }
    }
    if &p.here() == "$FPLIST" {
        p.next();
        // skip FPLIST for now
        while !p.eof() {
            if &p.here() == "$ENDFPLIST" {
                p.next();
                break;
            }
            p.next()
        }
    }
    assume_line!(p, "DRAW");
    while !p.eof() {
        let s2 = p.here();
        if &s2 == "ENDDRAW" {
            p.next();
            break;
        }
        s.draw.push(s2.clone());
        p.next()
    }
    assume_line!(p,"ENDDEF");
    assume_line!(p,"#");
    Ok(s)
}

fn bool_from<T: PartialEq + fmt::Display>(i:T, t:T, f:T) -> Result<bool> {
    if i == t {
        return Ok(true)
    }
    if i == f {
        return Ok(false)
    }
    str_error(format!("unknown boolean {}, expected {} or {}", i, t, f))
}

// F0 "L" 0 50 40 H V C CNN
fn parse_field(p:&mut ParseState, line:&str) -> Result<Field> {
    let mut f = Field::default();
    let v = &parse_split_quote_aware(line);
    if v.len() != 9 && v.len() != 10 {
        return str_error(format!("unexpected elements in {}", line))
    }
    f.i = try!(i64_from_string(p, &String::from(&v[0][1..])));
    let name = if v.len() == 10 {
        v[9].clone()
    } else {
        match f.i {
            0 => String::from("Reference"),
            1 => String::from("Value"),
            2 => String::from("Footprint"),
            3 => String::from("UserDocLink"),
            _ => return str_error("expecting name for componentfield > 3".to_string()),
        }
    };
    f.value = v[1].clone();
    f.x = try!(f64_from_string(p, &v[2]));
    f.y = try!(f64_from_string(p, &v[3]));
    f.dimension = try!(i64_from_string(p, &v[4]));
    f.orientation = try!(schematic::Orientation::new(char_at(&v[5], 0)));
    f.visible = try!(bool_from_string(&v[6], "V", "I"));
    f.hjustify = try!(schematic::Justify::new(char_at(&v[7], 0)));
    f.vjustify = try!(schematic::Justify::new(char_at(&v[8], 0)));
    f.italic = try!(bool_from(char_at(&v[8], 1), 'I', 'N'));
    f.bold = try!(bool_from(char_at(&v[8], 2), 'B', 'N'));
    f.name = name;
    Ok(f)
}

fn parse(s: &str) -> Result<SymbolLib> {
    let mut lib = SymbolLib::default();
    let v:Vec<&str> = s.lines().collect();
    let p = &mut ParseState::new(v);
    assume_line!(p, "EESchema-LIBRARY Version 2.3");
    assume_line!(p, "#encoding utf-8");
    assume_line!(p,"#");
    while !p.eof() {
        //println!("here: {}", &p.here());
        if &p.here() == "#End Library" {
            break;
        }
        let s = try!(parse_symbol(p));
        //println!("new symbol: {}", &s);
        lib.symbols.push(s)
    }
    Ok(lib)
}

pub fn parse_str(s:&str) -> Result<SymbolLib> {
    parse(s)
}

pub fn parse_file(filename:&PathBuf) -> Result<SymbolLib> {
    let name = filename.to_str().unwrap();
    let s = try!(read_file(name));
    parse(&s[..])
}
<commit_msg>set_name String -> &str<commit_after>// (c) 2016 Productize SPRL <joost@productize.be>

// extension: .lib
// format: old-style

use std::fmt;
use std::result;
use std::str::FromStr;
use std::path::PathBuf;

// get from parent
use Result;
use str_error as err;
use util::read_file;
use parse_split_quote_aware;
use schematic;
use str_error;

#[derive(Debug,Default)]
pub struct SymbolLib {
    pub symbols:Vec<Symbol>,
}

// DEF name reference unused text_offset draw_pinnumber draw_pinname unit_count units_locked option_flag
#[derive(Debug,Clone)]
pub struct Symbol {
    pub name:String,
    pub reference:String,
    pub text_offset:f64,
    pub draw_pinnumber: bool,
    pub draw_pinname: bool,
    pub unit_count: i64,
    pub unit_locked: bool,
    pub is_power: bool,
    pub fields:Vec<Field>,
    pub draw:Vec<String>, // TODO parse draw
}
// F n “text” posx posy dimension orientation visibility hjustify vjustify/italic/bold “name”
// F0 "#PWR" 0 0 30 H I C CNN

#[derive(Debug,Clone)]
pub struct Field {
    pub i:i64,
    pub value:String,
    pub x:f64,
    pub y:f64,
    pub dimension:i64,
    pub orientation:schematic::Orientation,
    pub visible:bool,
    pub hjustify:schematic::Justify,
    pub vjustify:schematic::Justify,
    pub italic:bool,
    pub bold:bool,
    pub name:String,
}

impl SymbolLib {
    pub fn find<F>(&self, filter:F) -> Option<&Symbol>
        where F:Fn(&Symbol) -> bool
    {
        for symbol in &self.symbols {
            if filter(symbol) {
                return Some(symbol)
            }
        }
        None
    }
}

impl fmt::Display for SymbolLib {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        try!(writeln!(f, "EESchema-LIBRARY Version 2.3"));
        try!(writeln!(f, "#encoding utf-8"));
        try!(writeln!(f, "#"));
        for i in &self.symbols {
            try!(write!(f, "{}", i))
        };
        writeln!(f, "#End Library")
    }
}

impl Symbol {
    pub fn new(name:String, reference:String) -> Symbol {
        Symbol {
            name:name,
            reference:reference,
            text_offset:0.0,
            draw_pinnumber:false,
            draw_pinname:false,
            unit_count:1,
            unit_locked:false,
            is_power:false,
            fields:vec![],
            draw:vec![],
        }
    }
    pub fn set_name(&mut self, name:&str) {
        if char_at(&self.name, 0) == '~' {
            self.name = format!("~{}", name)
        } else {
            self.name = name.to_string()
        }
        let mut field = &mut self.fields[1];
        field.value = name.to_string()
    }
}

impl fmt::Display for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        try!(writeln!(f, "# {}", &&self.fields[1].value));
        try!(writeln!(f, "#"));
        try!(writeln!(f, "DEF {} {} 0 {} {} {} {} {} {}",
                     self.name, self.reference, self.text_offset,
                     if self.draw_pinnumber { "Y" } else { "N" },
                     if self.draw_pinname { "Y" } else { "N" },
                     self.unit_count,
                     if self.unit_locked { "L" } else { "F" },
                     if self.is_power { "P" } else { "N" },
                     ));
        for field in &self.fields {
            try!(writeln!(f, "{}", field))
        };
        try!(writeln!(f, "DRAW"));
        for draw in &self.draw {
            try!(writeln!(f, "{}", draw))
        };
        try!(writeln!(f, "ENDDRAW"));
        try!(writeln!(f, "ENDDEF"));
        writeln!(f, "#")
    }
}

impl Default for Field {
    fn default() -> Field {
        Field {
            i:0,
            value:String::from(""),
            x:0.0,
            y:0.0,
            dimension:0,
            orientation:schematic::Orientation::Horizontal,
            visible:false,
            hjustify:schematic::Justify::Center,
            vjustify:schematic::Justify::Center,
            italic:false,
            bold:false,
            name:String::from(""),
        }
    }
}

impl fmt::Display for Field {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        try!(write!(f, "F{} \"{}\" {} {} {} {} {} {} {}{}{}",
               self.i, self.value, self.x, self.y, self.dimension,
               self.orientation,
               if self.visible { "V" } else { "I" },
               self.hjustify, self.vjustify,
               if self.italic { "I" } else { "N" },
               if self.bold { "I" } else { "N" },
                    ));
        if self.i > 3 {
            try!(write!(f, " \"{}\"", self.name))
        };
        Ok(())
    }
}

macro_rules! assume_line {
    ($s:expr, $exp:expr) => (
        if $s.eof() {
            return str_error("end of file reached".to_string())
        }
        if $s.here() != $exp {
            return str_error(format!("expected '{}', got '{}'", $exp, $s.here()))
        }
        $s.i += 1;
    )
}

#[derive(Debug)]
struct ParseState {
    i:usize,
    v:Vec<String>,
}

impl ParseState {
    fn new(v2:Vec<&str>) -> ParseState {
        ParseState {
            i:0,
            v:v2.iter().map(|x| String::from(*x)).collect(),
        }
    }

    fn here(&self) -> String {
        (self.v[self.i]).clone()
    }

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

    fn eof(&self) -> bool {
        self.i >= self.v.len()
    }
}

fn assume_string(e:&'static str, s:&str) -> Result<()> {
    if *e != *s {
        return str_error(format!("expecting: {}, actually: {}", e, s))
    }
    Ok(())
}

fn i64_from_string(p:&ParseState, s:&str) -> Result<i64> {
    match i64::from_str(s) {
        Ok(i) => Ok(i),
        _ => str_error(format!("int parse error in {}; line: {}", s, p.here()))
    }
}

fn f64_from_string(p:&ParseState, s:&str) -> Result<f64> {
    match f64::from_str(s) {
        Ok(i) => Ok(i),
        _ => str_error(format!("float parse error in {}; line: {}", s, p.here()))
    }
}

fn bool_from_string(s:&str, t:&'static str, f:&'static str) -> Result<bool> {
    if &s[..] == t {
        return Ok(true)
    }
    if &s[..] == f {
        return Ok(false)
    }
    str_error(format!("unknown boolean {}, expected {} or {}", s, t, f))
}

fn char_at(s:&str, p:usize) -> char {
    let v:Vec<char> = s.chars().collect();
    v[..][p]
}

fn parse_symbol(p:&mut ParseState) -> Result<Symbol> {
    p.next(); // skip line like # name
    assume_line!(p,"#");
    let s = p.here();
    let v = &parse_split_quote_aware(&s);
    if v.len() != 10 {
        return str_error(format!("unexpected elements in {}", s))
    }
    try!(assume_string("DEF", &v[0]));
    let mut s = Symbol::new(v[1].clone(), v[2].clone());
    s.text_offset = try!(f64_from_string(p, &v[4]));
    s.draw_pinnumber = try!(bool_from_string(&v[5], "Y", "N"));
    s.draw_pinname = try!(bool_from_string(&v[6], "Y", "N"));
    s.unit_count = try!(i64_from_string(p, &v[7]));
    s.unit_locked = try!(bool_from_string(&v[8], "L", "F"));
    s.is_power = try!(bool_from_string(&v[9], "P", "N"));
    // TODO fields
    // TODO draw
    p.next();
    loop {
        let s2 = p.here();
        if char_at(&s2, 0) == 'F' {
            let f = try!(parse_field(p, &s2));
            s.fields.push(f);
            p.next();
        } else {
            break;
        }
    }
    if &p.here() == "$FPLIST" {
        p.next();
        // skip FPLIST for now
        while !p.eof() {
            if &p.here() == "$ENDFPLIST" {
                p.next();
                break;
            }
            p.next()
        }
    }
    assume_line!(p, "DRAW");
    while !p.eof() {
        let s2 = p.here();
        if &s2 == "ENDDRAW" {
            p.next();
            break;
        }
        s.draw.push(s2.clone());
        p.next()
    }
    assume_line!(p,"ENDDEF");
    assume_line!(p,"#");
    Ok(s)
}

fn bool_from<T: PartialEq + fmt::Display>(i:T, t:T, f:T) -> Result<bool> {
    if i == t {
        return Ok(true)
    }
    if i == f {
        return Ok(false)
    }
    str_error(format!("unknown boolean {}, expected {} or {}", i, t, f))
}

// F0 "L" 0 50 40 H V C CNN
fn parse_field(p:&mut ParseState, line:&str) -> Result<Field> {
    let mut f = Field::default();
    let v = &parse_split_quote_aware(line);
    if v.len() != 9 && v.len() != 10 {
        return str_error(format!("unexpected elements in {}", line))
    }
    f.i = try!(i64_from_string(p, &String::from(&v[0][1..])));
    let name = if v.len() == 10 {
        v[9].clone()
    } else {
        match f.i {
            0 => String::from("Reference"),
            1 => String::from("Value"),
            2 => String::from("Footprint"),
            3 => String::from("UserDocLink"),
            _ => return str_error("expecting name for componentfield > 3".to_string()),
        }
    };
    f.value = v[1].clone();
    f.x = try!(f64_from_string(p, &v[2]));
    f.y = try!(f64_from_string(p, &v[3]));
    f.dimension = try!(i64_from_string(p, &v[4]));
    f.orientation = try!(schematic::Orientation::new(char_at(&v[5], 0)));
    f.visible = try!(bool_from_string(&v[6], "V", "I"));
    f.hjustify = try!(schematic::Justify::new(char_at(&v[7], 0)));
    f.vjustify = try!(schematic::Justify::new(char_at(&v[8], 0)));
    f.italic = try!(bool_from(char_at(&v[8], 1), 'I', 'N'));
    f.bold = try!(bool_from(char_at(&v[8], 2), 'B', 'N'));
    f.name = name;
    Ok(f)
}

fn parse(s: &str) -> Result<SymbolLib> {
    let mut lib = SymbolLib::default();
    let v:Vec<&str> = s.lines().collect();
    let p = &mut ParseState::new(v);
    assume_line!(p, "EESchema-LIBRARY Version 2.3");
    assume_line!(p, "#encoding utf-8");
    assume_line!(p,"#");
    while !p.eof() {
        //println!("here: {}", &p.here());
        if &p.here() == "#End Library" {
            break;
        }
        let s = try!(parse_symbol(p));
        //println!("new symbol: {}", &s);
        lib.symbols.push(s)
    }
    Ok(lib)
}

pub fn parse_str(s:&str) -> Result<SymbolLib> {
    parse(s)
}

pub fn parse_file(filename:&PathBuf) -> Result<SymbolLib> {
    let name = filename.to_str().unwrap();
    let s = try!(read_file(name));
    parse(&s[..])
}
<|endoftext|>


<commit_before>//! A simple adaptive threadpool that returns a oneshot future.

use std::{
    collections::VecDeque,
    sync::atomic::AtomicBool,
    thread,
    time::{Duration, Instant},
};

use parking_lot::{Condvar, Mutex};

use crate::{debug_delay, warn, AtomicUsize, Lazy, OneShot, Relaxed, SeqCst};

// This is lower for CI reasons.
#[cfg(windows)]
const MAX_THREADS: usize = 16;

#[cfg(not(windows))]
const MAX_THREADS: usize = 128;

const DESIRED_WAITING_THREADS: usize = 2;

static WAITING_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static TOTAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static SPAWNS: AtomicUsize = AtomicUsize::new(1);

macro_rules! once {
    ($args:block) => {
        static E: AtomicBool = AtomicBool::new(false);
        if !E.compare_and_swap(false, true, Relaxed) {
            // only execute this once
            $args;
        }
    };
}

type Work = Box<dyn FnOnce() + Send + 'static>;

struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        let cutoff = Instant::now() + duration;

        while queue.is_empty() {
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            let res = self.cv.wait_until(&mut queue, cutoff);
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            if res.timed_out() {
                break;
            }
        }

        queue.pop_front()
    }

    fn try_recv(&self) -> Option<Work> {
        let mut queue = self.mu.lock();
        queue.pop_front()
    }

    fn send(&self, work: Work) {
        let mut queue = self.mu.lock();
        queue.push_back(work);

        // having held the mutex makes this linearized
        // with the notify below.
        drop(queue);

        self.cv.notify_one();
    }
}

static QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(init_queue);

fn init_queue() -> Queue {
    maybe_spawn_new_thread();
    Queue { cv: Condvar::new(), mu: Mutex::new(VecDeque::new()) }
}

fn perform_work() {
    let wait_limit = Duration::from_secs(1);

    while WAITING_THREAD_COUNT.load(SeqCst) < DESIRED_WAITING_THREADS {
        debug_delay();
        let task_res = QUEUE.recv_timeout(wait_limit);

        if let Some(task) = task_res {
            (task)();
        }

        while let Some(task) = QUEUE.try_recv() {
            debug_delay();
            (task)();
        }

        debug_delay();
    }
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_spawn_new_thread() {
    debug_delay();
    let total_workers = TOTAL_THREAD_COUNT.load(SeqCst);
    debug_delay();
    let waiting_threads = WAITING_THREAD_COUNT.load(SeqCst);
    if waiting_threads >= DESIRED_WAITING_THREADS
        || total_workers >= MAX_THREADS
    {
        return;
    }

    let spawn_id = SPAWNS.fetch_add(1, Relaxed);
    let spawn_res = thread::Builder::new()
        .name(format!("sled-io-{}", spawn_id))
        .spawn(|| {
            debug_delay();
            TOTAL_THREAD_COUNT.fetch_add(1, SeqCst);
            perform_work();
            TOTAL_THREAD_COUNT.fetch_sub(1, SeqCst);
        });

    if let Err(e) = spawn_res {
        once!({
            warn!(
                "Failed to dynamically increase the threadpool size: {:?}. \
                 Currently have {} running IO threads",
                e, total_workers
            )
        });
    }
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> OneShot<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    QUEUE.send(Box::new(task));

    maybe_spawn_new_thread();

    promise
}
<commit_msg>Tune threadpool to avoid lots of churn<commit_after>//! A simple adaptive threadpool that returns a oneshot future.

use std::{
    collections::VecDeque,
    sync::atomic::AtomicBool,
    thread,
    time::{Duration, Instant},
};

use parking_lot::{Condvar, Mutex};

use crate::{debug_delay, warn, AtomicUsize, Lazy, OneShot, Relaxed, SeqCst};

// This is lower for CI reasons.
#[cfg(windows)]
const MAX_THREADS: usize = 16;

#[cfg(not(windows))]
const MAX_THREADS: usize = 128;

const DESIRED_WAITING_THREADS: usize = 4;

static WAITING_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static TOTAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static SPAWNS: AtomicUsize = AtomicUsize::new(0);
static SPAWNING: AtomicBool = AtomicBool::new(false);

macro_rules! once {
    ($args:block) => {
        static E: AtomicBool = AtomicBool::new(false);
        if !E.compare_and_swap(false, true, Relaxed) {
            // only execute this once
            $args;
        }
    };
}

type Work = Box<dyn FnOnce() + Send + 'static>;

struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        let cutoff = Instant::now() + duration;

        while queue.is_empty() {
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            let res = self.cv.wait_until(&mut queue, cutoff);
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            if res.timed_out() {
                break;
            }
        }

        queue.pop_front()
    }

    fn try_recv(&self) -> Option<Work> {
        let mut queue = self.mu.lock();
        queue.pop_front()
    }

    fn send(&self, work: Work) -> usize {
        let mut queue = self.mu.lock();
        queue.push_back(work);

        let len = queue.len();

        // having held the mutex makes this linearized
        // with the notify below.
        drop(queue);

        self.cv.notify_all();

        len
    }
}

static QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(init_queue);

fn init_queue() -> Queue {
    for _ in 1..DESIRED_WAITING_THREADS {
        maybe_spawn_new_thread();
    }
    Queue { cv: Condvar::new(), mu: Mutex::new(VecDeque::new()) }
}

fn perform_work() {
    let wait_limit = Duration::from_secs(1);

    let mut performed = 0;
    let mut contiguous_overshoots = 0;

    while performed < 5 || contiguous_overshoots < 3 {
        debug_delay();
        let task_res = QUEUE.recv_timeout(wait_limit);

        if let Some(task) = task_res {
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        while let Some(task) = QUEUE.try_recv() {
            debug_delay();
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        debug_delay();

        let waiting = WAITING_THREAD_COUNT.load(SeqCst);

        if waiting > DESIRED_WAITING_THREADS {
            contiguous_overshoots += 1;
        } else {
            contiguous_overshoots = 0;
        }
    }
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_spawn_new_thread() {
    debug_delay();
    let total_workers = TOTAL_THREAD_COUNT.load(SeqCst);
    debug_delay();
    let waiting_threads = WAITING_THREAD_COUNT.load(SeqCst);

    if waiting_threads >= DESIRED_WAITING_THREADS
        || total_workers >= MAX_THREADS
    {
        return;
    }

    if SPAWNING.compare_and_swap(false, true, SeqCst) == false {
        spawn_new_thread();
    }
}

fn spawn_new_thread() {
    let spawn_id = SPAWNS.fetch_add(1, SeqCst);

    TOTAL_THREAD_COUNT.fetch_add(1, SeqCst);
    let spawn_res = thread::Builder::new()
        .name(format!("sled-io-{}", spawn_id))
        .spawn(|| {
            SPAWNING.store(false, SeqCst);
            debug_delay();
            perform_work();
            TOTAL_THREAD_COUNT.fetch_sub(1, SeqCst);
        });

    if let Err(e) = spawn_res {
        SPAWNING.store(false, SeqCst);
        once!({
            warn!(
                "Failed to dynamically increase the threadpool size: {:?}.",
                e,
            )
        });
    }
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> OneShot<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    let depth = QUEUE.send(Box::new(task));

    if depth > DESIRED_WAITING_THREADS {
        maybe_spawn_new_thread();
    }

    promise
}
<|endoftext|>


<commit_before>#![crate_name = "uu_factor"]

/*
* This file is part of the uutils coreutils package.
*
* (c) T. Jameson Little <t.jameson.little@gmail.com>
* (c) Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
*     20150223 added Pollard rho method implementation
* (c) kwantam <kwantam@gmail.com>
*     20150429 sped up trial division by adding table of prime inverses
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

extern crate rand;

#[macro_use]
extern crate uucore;

use std::collections::HashMap;
use std::fmt;
use std::io::{stdin, BufRead};
use std::ops;

mod miller_rabin;
mod numeric;
mod rho;
mod table;

static SYNTAX: &str = "[OPTION] [NUMBER]...";
static SUMMARY: &str = "Print the prime factors of the given number(s).
 If none are specified, read from standard input.";
static LONG_HELP: &str = "";

struct Factors {
    f: HashMap<u64, u8>,
}

impl Factors {
    fn new() -> Factors {
        Factors { f: HashMap::new() }
    }

    fn add(&mut self, prime: u64, exp: u8) {
        assert!(exp > 0);
        self.f.insert(prime, exp + self.f.get(&prime).unwrap_or(&0));
    }

    fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }
}

impl ops::MulAssign<Factors> for Factors {
    fn mul_assign(&mut self, other: Factors) {
        for (prime, exp) in &other.f {
            self.add(*prime, *exp);
        }
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // TODO: Use a representation with efficient in-order iteration
        let mut primes: Vec<&u64> = self.f.keys().collect();
        primes.sort();

        for p in primes {
            for _ in 0..self.f[&p] {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn factor(mut n: u64) -> Factors {
    let mut factors = Factors::new();

    if n < 2 {
        factors.push(n);
        return factors;
    }

    let z = n.trailing_zeros();
    if z > 0 {
        factors.add(2, z as u8);
        n >>= z;
    }

    if n == 1 {
        return factors;
    }

    let (f, n) = table::factor(n);
    factors *= f;

    if n >= table::NEXT_PRIME {
        factors *= rho::factor(n);
    }

    factors
}

fn print_factors(num: u64) {
    print!("{}:{}", num, factor(num));
    println!();
}

fn print_factors_str(num_str: &str) {
    if let Err(e) = num_str.parse::<u64>().and_then(|x| {
        print_factors(x);
        Ok(())
    }) {
        show_warning!("{}: {}", num_str, e);
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);

    if matches.free.is_empty() {
        let stdin = stdin();
        for line in stdin.lock().lines() {
            for number in line.unwrap().split_whitespace() {
                print_factors_str(number);
            }
        }
    } else {
        for num_str in &matches.free {
            print_factors_str(num_str);
        }
    }
    0
}
<commit_msg>factor::Factors::add: Split up to work without NLL<commit_after>#![crate_name = "uu_factor"]

/*
* This file is part of the uutils coreutils package.
*
* (c) T. Jameson Little <t.jameson.little@gmail.com>
* (c) Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
*     20150223 added Pollard rho method implementation
* (c) kwantam <kwantam@gmail.com>
*     20150429 sped up trial division by adding table of prime inverses
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

extern crate rand;

#[macro_use]
extern crate uucore;

use std::collections::HashMap;
use std::fmt;
use std::io::{stdin, BufRead};
use std::ops;

mod miller_rabin;
mod numeric;
mod rho;
mod table;

static SYNTAX: &str = "[OPTION] [NUMBER]...";
static SUMMARY: &str = "Print the prime factors of the given number(s).
 If none are specified, read from standard input.";
static LONG_HELP: &str = "";

struct Factors {
    f: HashMap<u64, u8>,
}

impl Factors {
    fn new() -> Factors {
        Factors { f: HashMap::new() }
    }

    fn add(&mut self, prime: u64, exp: u8) {
        assert!(exp > 0);
        let n = *self.f.get(&prime).unwrap_or(&0);
        self.f.insert(prime, exp + n);
    }

    fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }
}

impl ops::MulAssign<Factors> for Factors {
    fn mul_assign(&mut self, other: Factors) {
        for (prime, exp) in &other.f {
            self.add(*prime, *exp);
        }
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // TODO: Use a representation with efficient in-order iteration
        let mut primes: Vec<&u64> = self.f.keys().collect();
        primes.sort();

        for p in primes {
            for _ in 0..self.f[&p] {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn factor(mut n: u64) -> Factors {
    let mut factors = Factors::new();

    if n < 2 {
        factors.push(n);
        return factors;
    }

    let z = n.trailing_zeros();
    if z > 0 {
        factors.add(2, z as u8);
        n >>= z;
    }

    if n == 1 {
        return factors;
    }

    let (f, n) = table::factor(n);
    factors *= f;

    if n >= table::NEXT_PRIME {
        factors *= rho::factor(n);
    }

    factors
}

fn print_factors(num: u64) {
    print!("{}:{}", num, factor(num));
    println!();
}

fn print_factors_str(num_str: &str) {
    if let Err(e) = num_str.parse::<u64>().and_then(|x| {
        print_factors(x);
        Ok(())
    }) {
        show_warning!("{}: {}", num_str, e);
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);

    if matches.free.is_empty() {
        let stdin = stdin();
        for line in stdin.lock().lines() {
            for number in line.unwrap().split_whitespace() {
                print_factors_str(number);
            }
        }
    } else {
        for num_str in &matches.free {
            print_factors_str(num_str);
        }
    }
    0
}
<|endoftext|>


<commit_before>
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum Color {
    Black      = 0,
    Blue       = 1,
    Green      = 2,
    Cyan       = 3,
    Red        = 4,
    Magenta    = 5,
    Brown      = 6,
    LightGray  = 7,
    DarkGray   = 8,
    LightBlue  = 9,
    LightGreen = 10,
    LightCyan  = 11,
    LightRed   = 12,
    Pink       = 13,
    Yellow     = 14,
    White      = 15,
}

#[derive(Debug, Clone, Copy)]
struct ColorCode(u8);

impl ColorCode {
  const fn new(fg: Color, bg: Color) -> ColorCode {
    ColorCode((bg as u8) << 4 | (fg as u8))
  }
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct ScreenChar {
  ascii_char : u8,
  color : ColorCode,
}

const BUFFER_HEIGHT : usize = 25;
const BUFFER_WIDTH  : usize = 80;

use volatile::Volatile;

struct Buffer {
  chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT]
}

use core::ptr::Unique;

pub struct Writer {
   col_pos : usize,
   color_code : ColorCode,
   buffer: Unique<Buffer>,
}

impl Writer {

  fn newline(&mut self) {
     // TODO
  }

  fn buffer(&mut self) -> &mut Buffer {
    unsafe { self.buffer.get_mut() }
  }

  pub fn write_byte(&mut self, byte : u8) {
    match byte {
       b'\n' => self.newline(),
       byte => {
         if (self.col_pos >= BUFFER_WIDTH) {
           self.newline();
         }

         let row = BUFFER_HEIGHT - 1;
         let col = self.col_pos;

         let cc = self.color_code;
         self.buffer().chars[row][col].write(ScreenChar {
           ascii_char: byte,
           color : cc
         });
         self.col_pos +=1;
       }
    }
  }
}

use core::fmt;

impl fmt::Write for Writer {
  fn write_str(&mut self, s: &str) -> fmt::Result {
    for byte in s.bytes() {
      self.write_byte(byte);
    }
    Ok(())
  }
}

pub fn print_something() {
  use core::fmt::Write;
  let mut writer = Writer {
    col_pos : 0,
    color_code : ColorCode::new(Color::LightGreen, Color::Black),
    buffer: unsafe { Unique::new(0xb8000 as *mut _) },
  };
  writer.write_byte(b'H');
  writer.write_str("ello!\n");
  write!(writer, "The numbers are {} and {}", 42, 1.0/3.0);
}

pub static mut VGA : Writer = Writer {
  col_pos : 0,
  color_code : ColorCode::new(Color::White, Color::Black),
  buffer: unsafe { Unique::new(0xb8000 as *mut _) },
};
<commit_msg>handle newline print in vga<commit_after>
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum Color {
    Black      = 0,
    Blue       = 1,
    Green      = 2,
    Cyan       = 3,
    Red        = 4,
    Magenta    = 5,
    Brown      = 6,
    LightGray  = 7,
    DarkGray   = 8,
    LightBlue  = 9,
    LightGreen = 10,
    LightCyan  = 11,
    LightRed   = 12,
    Pink       = 13,
    Yellow     = 14,
    White      = 15,
}

#[derive(Debug, Clone, Copy)]
struct ColorCode(u8);

impl ColorCode {
  const fn new(fg: Color, bg: Color) -> ColorCode {
    ColorCode((bg as u8) << 4 | (fg as u8))
  }
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct ScreenChar {
  ascii_char : u8,
  color : ColorCode,
}

const BUFFER_HEIGHT : usize = 25;
const BUFFER_WIDTH  : usize = 80;

use volatile::Volatile;

struct Buffer {
  chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT]
}

use core::ptr::Unique;

pub struct Writer {
   col_pos : usize,
   color_code : ColorCode,
   buffer: Unique<Buffer>,
}

impl Writer {

  fn newline(&mut self) {
    for row in 1..BUFFER_HEIGHT {
      for col in 0..BUFFER_WIDTH {
        let buffer = self.buffer();
        let character = buffer.chars[row][col].read();
        buffer.chars[row-1][col].write(character);
      }
    }
    self.clear_row(BUFFER_HEIGHT - 1);
    self.col_pos = 0;
  }

  fn clear_row(&mut self, row : usize) {
    let blank = ScreenChar {
      ascii_char : b' ',
      color : ColorCode::new(Color::White, Color::Black),
    };
    let buffer = self.buffer();
    for col in 0..BUFFER_WIDTH {
      buffer.chars[row][col].write(blank);
    }
  }

  fn buffer(&mut self) -> &mut Buffer {
    unsafe { self.buffer.get_mut() }
  }

  pub fn write_byte(&mut self, byte : u8) {
    match byte {
       b'\n' => self.newline(),
       byte => {
         if (self.col_pos >= BUFFER_WIDTH) {
           self.newline();
         }

         let row = BUFFER_HEIGHT - 1;
         let col = self.col_pos;

         let cc = self.color_code;
         self.buffer().chars[row][col].write(ScreenChar {
           ascii_char: byte,
           color : cc
         });
         self.col_pos +=1;
       }
    }
  }
}

use core::fmt;

impl fmt::Write for Writer {
  fn write_str(&mut self, s: &str) -> fmt::Result {
    for byte in s.bytes() {
      self.write_byte(byte);
    }
    Ok(())
  }
}

pub fn print_something() {
  use core::fmt::Write;
  let mut writer = Writer {
    col_pos : 0,
    color_code : ColorCode::new(Color::LightGreen, Color::Black),
    buffer: unsafe { Unique::new(0xb8000 as *mut _) },
  };
  writer.write_byte(b'H');
  writer.write_str("ello!\n");
  write!(writer, "The numbers are {} and {}", 42, 1.0/3.0);
}

pub static mut VGA : Writer = Writer {
  col_pos : 0,
  color_code : ColorCode::new(Color::White, Color::Black),
  buffer: unsafe { Unique::new(0xb8000 as *mut _) },
};
<|endoftext|>