<commit_before>//! Helper to crudely rewrite types from the spec's format to our own.
//!
//! This reads a file containing table and record descriptions (from the spec)
//! and converts them to the form that we use, writing the result to stdout.
//!
//! Input should be in the format:
//!
//!
//! ```
//! { // this is a 'group'
//! /// an optional comment for each top-level item
//! @table Gpos1_0
//! uint16      majorVersion       Major version of the GPOS table, = 1
//! uint16      minorVersion       Minor version of the GPOS table, = 0
//! Offset16    scriptListOffset   Offset to ScriptList table, from beginning of GPOS table
//! Offset16    featureListOffset  Offset to FeatureList table, from beginning of GPOS table
//! Offset16    lookupListOffset   Offset to LookupList table, from beginning of GPOS table
//!
//! @table Gpos1_1
//! uint16      majorVersion            Major version of the GPOS table, = 1
//! uint16      minorVersion            Minor version of the GPOS table, = 1
//! Offset16    scriptListOffset        Offset to ScriptList table, from beginning of GPOS table
//! Offset16    featureListOffset       Offset to FeatureList table, from beginning of GPOS table
//! Offset16    lookupListOffset        Offset to LookupList table, from beginning of GPOS table
//! Offset32    featureVariationsOffset Offset to FeatureVariations table, from beginning of GPOS table (may be NULL)
//! }
//! ```
//!
//! - different records/tables are separated by newlines.
//! - the first line should be a single word, used as the name of the type
//! - other lines are just copy pasted
//!
//! *limitations:* this doesn't handle lifetimes, and doesn't generate annotations.
//! You will need to clean up the output.

use std::{fmt::Write, ops::Deref};

macro_rules! exit_with_msg {
    ($disp:expr, $line:expr) => {{
        eprintln!("ERROR: {}", $disp);
        eprintln!("Line {}: '{}'", 1 + $line.number, $line.text);
        std::process::exit(1);
    }};
}

static MACRO_CALL: &str = "font_types::tables!";

/// a wrapper around a line, so we can report errors with line numbers
struct Line<'a> {
    text: &'a str,
    number: usize,
}

impl Deref for Line<'_> {
    type Target = str;
    fn deref(&self) -> &<Self as Deref>::Target {
        self.text
    }
}

fn main() {
    let in_path = std::env::args().nth(1).expect("expected path argument");
    let input = std::fs::read_to_string(in_path).expect("failed to read path");
    let mut lines = input
        .lines()
        .enumerate()
        .map(|(number, text)| Line {
            text: text.trim(),
            number,
        })
        .filter(|l| !l.starts_with('#'));

    while let Some(group) = generate_group(&mut lines) {
        println!("\n{} {{", MACRO_CALL);
        println!("{}", group);
        println!("}}");
    }
}

/// Generate a group of items. This is multiple items within a pair of brackets,
/// which will share a single macro invocation.
fn generate_group<'a>(lines: impl Iterator<Item = Line<'a>>) -> Option<String> {
    let mut lines = lines.skip_while(|s| s.is_empty()).peekable();
    let brace = lines.next()?;

    let mut result = String::new();

    if !brace.starts_with('{') {
        exit_with_msg!("expected opening brace", brace);
    }

    let mut lines = lines.take_while(|line| !line.starts_with('}'));

    while let Some(item) = generate_one_item(&mut lines) {
        if !result.is_empty() {
            result.push_str("\n\n");
        }
        result.push_str(&item);
    }
    Some(result)
}

/// parse a single enum, table or record.
///
/// Returns `Some` on success, `None` if there are no more items, and terminates
/// if something goes wrong.
fn generate_one_item<'a>(lines: impl Iterator<Item = Line<'a>>) -> Option<String> {
    let mut lines = lines.skip_while(|line| line.is_empty());
    let mut comments = Vec::new();
    let decl = loop {
        match lines.next() {
            Some(line) if line.starts_with("///") => comments.push(line.text),
            Some(line) if line.starts_with('@') => break Decl::parse(line).unwrap(),
            Some(line) => exit_with_msg!("expected table or record name", line),
            None => return None,
        }
    };

    let item = match decl.kind {
        DeclKind::RawEnum => generate_one_enum(decl, lines),
        DeclKind::Table | DeclKind::Record => generate_one_table(decl, lines),
        DeclKind::Flags => generate_one_flags(decl, lines),
    }?;
    let mut comments = comments.join("\n");
    if comments.is_empty() {
        Some(item)
    } else {
        comments.push('\n');
        comments.push_str(&item);
        Some(comments)
    }
}

/// Generate a single table or record (they're currently the same)
fn generate_one_table<'a>(decl: Decl, lines: impl Iterator<Item = Line<'a>>) -> Option<String> {
    let fields = lines.map_while(parse_field).collect::<Vec<_>>();
    let lifetime_str = if fields.iter().any(|x| x.maybe_count.is_some()) {
        "<'a>"
    } else {
        ""
    };
    let mut result = String::new();
    writeln!(&mut result, "{}{} {{", decl.name, lifetime_str).unwrap();
    for line in &fields {
        writeln!(&mut result, "{}", line).unwrap();
    }
    result.push('}');
    Some(result)
}

fn generate_one_enum<'a>(decl: Decl, lines: impl Iterator<Item = Line<'a>>) -> Option<String> {
    let fields = lines.map_while(parse_field).collect::<Vec<_>>();
    let mut result = String::new();
    writeln!(
        &mut result,
        "#[repr({})]\nenum {} {{",
        decl.annotation, decl.name
    )
    .unwrap();
    for line in &fields {
        writeln!(&mut result, "    {} = {},", line.name, line.typ).unwrap();
    }
    result.push('}');
    Some(result)
}

fn generate_one_flags<'a>(decl: Decl, lines: impl Iterator<Item = Line<'a>>) -> Option<String> {
    let fields = lines.map_while(parse_field).collect::<Vec<_>>();
    let mut result = String::new();
    writeln!(
        &mut result,
        "#[flags({})]\n{} {{",
        decl.annotation, decl.name
    )
    .unwrap();
    for line in &fields {
        format_comment(&mut result, "    ", line.comment).unwrap();
        writeln!(&mut result, "    {} = {},", line.name, line.typ).unwrap();
    }
    result.push('}');
    Some(result)
}

enum DeclKind {
    Table,
    Record,
    RawEnum,
    Flags,
}

struct Decl<'a> {
    kind: DeclKind,
    annotation: &'a str,
    name: &'a str,
}

impl<'a> Decl<'a> {
    fn parse(line: Line<'a>) -> Option<Self> {
        let mut decl = line.text.split_whitespace();
        let mut annotation = "";
        let kind = match decl.next()? {
            "@table" => DeclKind::Table,
            "@record" => DeclKind::Record,
            x if x.starts_with("@enum(") || x.starts_with("@flags(") => {
                let repr = x.split_once('(').unwrap().1.trim_end_matches(')');
                //let repr = x.trim_start_matches("@enum(").trim_end_matches(')');
                if !["u8", "u16"].contains(&repr) {
                    exit_with_msg!(format!("unexpected enum/flag repr '{}'", repr), line);
                }
                annotation = repr;
                if x.starts_with("@enum") {
                    DeclKind::RawEnum
                } else {
                    DeclKind::Flags
                }
            }
            other => exit_with_msg!(format!("unknown item kind '{}'", other), line),
        };
        let name = decl
            .next()
            .unwrap_or_else(|| exit_with_msg!("missing name", line));

        Some(Decl {
            kind,
            annotation,
            name,
        })
    }
}

struct Field<'a> {
    name: &'a str,
    maybe_count: Option<String>,
    typ: &'a str,
    comment: &'a str,
}

impl<'a> std::fmt::Display for Field<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        format_comment(f, "    ", self.comment)?;
        if self.name.contains("reserved") {
            writeln!(f, "    #[hidden]")?;
        }
        if let Some(count) = &self.maybe_count {
            writeln!(f, "    #[count({})]", count)?;
            write!(f, "    {}: [{}],", decamalize(self.name), self.typ)?;
        } else {
            write!(f, "    {}: {},", decamalize(self.name), self.typ)?;
        }
        Ok(())
    }
}

fn parse_field(line: Line) -> Option<Field> {
    if line.is_empty() {
        return None;
    }
    let mut iter = line.text.splitn(3, '\t');
    let (typ, ident, comment) = match (iter.next(), iter.next(), iter.next()) {
        (Some(a), Some(b), Some(c)) => (a, b, c),
        (Some(a), Some(b), None) => (a, b, ""),
        _ => exit_with_msg!("line could not be parsed as type/name/comment", line),
    };
    let typ = normalize_type(typ);
    let (name, maybe_count) = split_ident(ident);
    //let name = decamalize(name);
    let maybe_count = maybe_count.map(decamalize);
    Some(Field {
        name,
        maybe_count,
        typ,
        comment,
    })
}

/// takes an ident and splits it into the name and an optional count (if the item
/// is an array)
fn split_ident(input: &str) -> (&str, Option<&str>) {
    match input.split_once('[') {
        Some((front, back)) => (front, Some(back.trim_end_matches(']'))),
        None => (input, None),
    }
}

fn normalize_type(input: &str) -> &str {
    match input {
        "uint8" => "BigEndian<u8>",
        "uint16" => "BigEndian<u16>",
        "uint24" => "BigEndian<Uint24>",
        "uint32" => "BigEndian<u32>",
        "int8" => "BigEndian<i8>",
        "int16" => "BigEndian<i16>",
        "int32" => "BigEndian<i32>",
        "FWORD" => "BigEndian<FWord>",
        "UFWORD" => "BigEndian<UfWord>",
        "F2DOT14" => "BigEndian<F2Dot14>",
        "LONGDATETIME" => "BigEndian<LongDateTime>",
        "Version16Dot16" => "BigEndian<Version16Dot16>",
        "Fixed" => "BigEndian<Fixed>",
        "Tag" => "BigEndian<Tag>",
        "Offset16" => "BigEndian<Offset16>",
        "Offset24" => "BigEndian<Offset24>",
        "Offset32" => "BigEndian<Offset32>",
        other => other,
    }
}

fn decamalize(input: &str) -> String {
    //taken from serde: https://github.com/serde-rs/serde/blob/7e19ae8c9486a3bbbe51f1befb05edee94c454f9/serde_derive/src/internals/case.rs#L69-L76
    let mut snake = String::new();
    for (i, ch) in input.char_indices() {
        if i > 0 && ch.is_uppercase() {
            snake.push('_');
        }
        snake.push(ch.to_ascii_lowercase());
    }
    snake
}

fn format_comment(f: &mut dyn std::fmt::Write, whitespace: &str, input: &str) -> std::fmt::Result {
    const LINE_LEN: usize = 72;

    let mut cur_len = 0;

    for token in input.split_inclusive(' ') {
        if cur_len == 0 || cur_len + token.len() > LINE_LEN {
            if cur_len > 0 {
                writeln!(f)?;
            }
            write!(f, "{}/// ", whitespace)?;
            cur_len = whitespace.len() + 4;
        }
        write!(f, "{}", token)?;
        cur_len += token.len();
    }
    if cur_len > 0 {
        writeln!(f)?;
    }
    Ok(())
}
<commit_msg>[codegen] make braces optional<commit_after>//! Helper to crudely rewrite types from the spec's format to our own.
//!
//! This reads a file containing table and record descriptions (from the spec)
//! and converts them to the form that we use, writing the result to stdout.
//!
//! Input should be in the format:
//!
//!
//! ```
//! { // braces can be used to group items into multiple macro invocations
//! /// an optional comment for each top-level item
//! @table Gpos1_0
//! uint16      majorVersion       Major version of the GPOS table, = 1
//! uint16      minorVersion       Minor version of the GPOS table, = 0
//! Offset16    scriptListOffset   Offset to ScriptList table, from beginning of GPOS table
//! Offset16    featureListOffset  Offset to FeatureList table, from beginning of GPOS table
//! Offset16    lookupListOffset   Offset to LookupList table, from beginning of GPOS table
//!
//! @table Gpos1_1
//! uint16      majorVersion            Major version of the GPOS table, = 1
//! uint16      minorVersion            Minor version of the GPOS table, = 1
//! Offset16    scriptListOffset        Offset to ScriptList table, from beginning of GPOS table
//! Offset16    featureListOffset       Offset to FeatureList table, from beginning of GPOS table
//! Offset16    lookupListOffset        Offset to LookupList table, from beginning of GPOS table
//! Offset32    featureVariationsOffset Offset to FeatureVariations table, from beginning of GPOS table (may be NULL)
//! }
//! ```
//!
//! - different records/tables are separated by newlines.
//! - the first line should be a single word, used as the name of the type
//! - other lines are just copy pasted
//!
//! *limitations:* this doesn't handle lifetimes, and doesn't generate annotations.
//! You will need to clean up the output.

use std::{fmt::Write, ops::Deref};

macro_rules! exit_with_msg {
    ($disp:expr, $line:expr) => {{
        eprintln!("ERROR: {}", $disp);
        eprintln!("Line {}: '{}'", 1 + $line.number, $line.text);
        std::process::exit(1);
    }};
}

static MACRO_CALL: &str = "font_types::tables!";

/// a wrapper around a line, so we can report errors with line numbers
struct Line<'a> {
    text: &'a str,
    number: usize,
}

impl Deref for Line<'_> {
    type Target = str;
    fn deref(&self) -> &<Self as Deref>::Target {
        self.text
    }
}

fn main() {
    let in_path = std::env::args().nth(1).expect("expected path argument");
    let input = std::fs::read_to_string(in_path).expect("failed to read path");
    let mut lines = input
        .lines()
        .enumerate()
        .map(|(number, text)| Line {
            text: text.trim(),
            number,
        })
        .filter(|l| !l.starts_with('#'));

    while let Some(group) = generate_group(&mut lines) {
        println!("\n{} {{", MACRO_CALL);
        println!("{}", group);
        println!("}}");
    }
}

/// Generate a group of items. This is multiple items within a pair of brackets,
/// which will share a single macro invocation.
fn generate_group<'a>(lines: impl Iterator<Item = Line<'a>>) -> Option<String> {
    let mut lines = lines.skip_while(|s| s.is_empty()).peekable();

    // if this is an explicit group, discard the brace line
    if lines.peek()?.starts_with('{') {
        let _ = lines.next();
    }

    let mut result = String::new();

    // stop at closing brace if it exists; if it doesn't we just consume all items
    let mut lines = lines.take_while(|line| !line.starts_with(&['{', '}']));

    while let Some(item) = generate_one_item(&mut lines) {
        if !result.is_empty() {
            result.push_str("\n\n");
        }
        result.push_str(&item);
    }
    Some(result)
}

/// parse a single enum, table or record.
///
/// Returns `Some` on success, `None` if there are no more items, and terminates
/// if something goes wrong.
fn generate_one_item<'a>(lines: impl Iterator<Item = Line<'a>>) -> Option<String> {
    let mut lines = lines.skip_while(|line| line.is_empty());
    let mut comments = Vec::new();
    let decl = loop {
        match lines.next() {
            Some(line) if line.starts_with("///") => comments.push(line.text),
            Some(line) if line.starts_with('@') => break Decl::parse(line).unwrap(),
            Some(line) => exit_with_msg!("expected table or record name", line),
            None => return None,
        }
    };

    let item = match decl.kind {
        DeclKind::RawEnum => generate_one_enum(decl, lines),
        DeclKind::Table | DeclKind::Record => generate_one_table(decl, lines),
        DeclKind::Flags => generate_one_flags(decl, lines),
    }?;
    let mut comments = comments.join("\n");
    if comments.is_empty() {
        Some(item)
    } else {
        comments.push('\n');
        comments.push_str(&item);
        Some(comments)
    }
}

/// Generate a single table or record (they're currently the same)
fn generate_one_table<'a>(decl: Decl, lines: impl Iterator<Item = Line<'a>>) -> Option<String> {
    let fields = lines.map_while(parse_field).collect::<Vec<_>>();
    let lifetime_str = if fields.iter().any(|x| x.maybe_count.is_some()) {
        "<'a>"
    } else {
        ""
    };
    let mut result = String::new();
    writeln!(&mut result, "{}{} {{", decl.name, lifetime_str).unwrap();
    for line in &fields {
        writeln!(&mut result, "{}", line).unwrap();
    }
    result.push('}');
    Some(result)
}

fn generate_one_enum<'a>(decl: Decl, lines: impl Iterator<Item = Line<'a>>) -> Option<String> {
    let fields = lines.map_while(parse_field).collect::<Vec<_>>();
    let mut result = String::new();
    writeln!(
        &mut result,
        "#[repr({})]\nenum {} {{",
        decl.annotation, decl.name
    )
    .unwrap();
    for line in &fields {
        writeln!(&mut result, "    {} = {},", line.name, line.typ).unwrap();
    }
    result.push('}');
    Some(result)
}

fn generate_one_flags<'a>(decl: Decl, lines: impl Iterator<Item = Line<'a>>) -> Option<String> {
    let fields = lines.map_while(parse_field).collect::<Vec<_>>();
    let mut result = String::new();
    writeln!(
        &mut result,
        "#[flags({})]\n{} {{",
        decl.annotation, decl.name
    )
    .unwrap();
    for line in &fields {
        format_comment(&mut result, "    ", line.comment).unwrap();
        writeln!(&mut result, "    {} = {},", line.name, line.typ).unwrap();
    }
    result.push('}');
    Some(result)
}

enum DeclKind {
    Table,
    Record,
    RawEnum,
    Flags,
}

struct Decl<'a> {
    kind: DeclKind,
    annotation: &'a str,
    name: &'a str,
}

impl<'a> Decl<'a> {
    fn parse(line: Line<'a>) -> Option<Self> {
        let mut decl = line.text.split_whitespace();
        let mut annotation = "";
        let kind = match decl.next()? {
            "@table" => DeclKind::Table,
            "@record" => DeclKind::Record,
            x if x.starts_with("@enum(") || x.starts_with("@flags(") => {
                let repr = x.split_once('(').unwrap().1.trim_end_matches(')');
                //let repr = x.trim_start_matches("@enum(").trim_end_matches(')');
                if !["u8", "u16"].contains(&repr) {
                    exit_with_msg!(format!("unexpected enum/flag repr '{}'", repr), line);
                }
                annotation = repr;
                if x.starts_with("@enum") {
                    DeclKind::RawEnum
                } else {
                    DeclKind::Flags
                }
            }
            other => exit_with_msg!(format!("unknown item kind '{}'", other), line),
        };
        let name = decl
            .next()
            .unwrap_or_else(|| exit_with_msg!("missing name", line));

        Some(Decl {
            kind,
            annotation,
            name,
        })
    }
}

struct Field<'a> {
    name: &'a str,
    maybe_count: Option<String>,
    typ: &'a str,
    comment: &'a str,
}

impl<'a> std::fmt::Display for Field<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        format_comment(f, "    ", self.comment)?;
        if self.name.contains("reserved") {
            writeln!(f, "    #[hidden]")?;
        }
        if let Some(count) = &self.maybe_count {
            writeln!(f, "    #[count({})]", count)?;
            write!(f, "    {}: [{}],", decamalize(self.name), self.typ)?;
        } else {
            write!(f, "    {}: {},", decamalize(self.name), self.typ)?;
        }
        Ok(())
    }
}

fn parse_field(line: Line) -> Option<Field> {
    if line.is_empty() {
        return None;
    }
    let mut iter = line.text.splitn(3, '\t');
    let (typ, ident, comment) = match (iter.next(), iter.next(), iter.next()) {
        (Some(a), Some(b), Some(c)) => (a, b, c),
        (Some(a), Some(b), None) => (a, b, ""),
        _ => exit_with_msg!("line could not be parsed as type/name/comment", line),
    };
    let typ = normalize_type(typ);
    let (name, maybe_count) = split_ident(ident);
    //let name = decamalize(name);
    let maybe_count = maybe_count.map(decamalize);
    Some(Field {
        name,
        maybe_count,
        typ,
        comment,
    })
}

/// takes an ident and splits it into the name and an optional count (if the item
/// is an array)
fn split_ident(input: &str) -> (&str, Option<&str>) {
    match input.split_once('[') {
        Some((front, back)) => (front, Some(back.trim_end_matches(']'))),
        None => (input, None),
    }
}

fn normalize_type(input: &str) -> &str {
    match input {
        "uint8" => "BigEndian<u8>",
        "uint16" => "BigEndian<u16>",
        "uint24" => "BigEndian<Uint24>",
        "uint32" => "BigEndian<u32>",
        "int8" => "BigEndian<i8>",
        "int16" => "BigEndian<i16>",
        "int32" => "BigEndian<i32>",
        "FWORD" => "BigEndian<FWord>",
        "UFWORD" => "BigEndian<UfWord>",
        "F2DOT14" => "BigEndian<F2Dot14>",
        "LONGDATETIME" => "BigEndian<LongDateTime>",
        "Version16Dot16" => "BigEndian<Version16Dot16>",
        "Fixed" => "BigEndian<Fixed>",
        "Tag" => "BigEndian<Tag>",
        "Offset16" => "BigEndian<Offset16>",
        "Offset24" => "BigEndian<Offset24>",
        "Offset32" => "BigEndian<Offset32>",
        other => other,
    }
}

fn decamalize(input: &str) -> String {
    //taken from serde: https://github.com/serde-rs/serde/blob/7e19ae8c9486a3bbbe51f1befb05edee94c454f9/serde_derive/src/internals/case.rs#L69-L76
    let mut snake = String::new();
    for (i, ch) in input.char_indices() {
        if i > 0 && ch.is_uppercase() {
            snake.push('_');
        }
        snake.push(ch.to_ascii_lowercase());
    }
    snake
}

fn format_comment(f: &mut dyn std::fmt::Write, whitespace: &str, input: &str) -> std::fmt::Result {
    const LINE_LEN: usize = 72;

    let mut cur_len = 0;

    for token in input.split_inclusive(' ') {
        if cur_len == 0 || cur_len + token.len() > LINE_LEN {
            if cur_len > 0 {
                writeln!(f)?;
            }
            write!(f, "{}/// ", whitespace)?;
            cur_len = whitespace.len() + 4;
        }
        write!(f, "{}", token)?;
        cur_len += token.len();
    }
    if cur_len > 0 {
        writeln!(f)?;
    }
    Ok(())
}
<|endoftext|>


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

use failure::prelude::*;
use libra_types::PeerId;
use rand::{rngs::StdRng, SeedableRng};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{
    fmt,
    fs::File,
    io::{Read, Write},
    path::{Path, PathBuf},
    sync::Arc,
};
use toml;

mod admission_control_config;
pub use admission_control_config::*;
mod consensus_config;
pub use consensus_config::*;
mod debug_interface_config;
pub use debug_interface_config::*;
mod execution_config;
pub use execution_config::*;
mod logger_config;
pub use logger_config::*;
mod metrics_config;
pub use metrics_config::*;
mod mempool_config;
pub use mempool_config::*;
mod network_config;
pub use network_config::*;
mod state_sync_config;
pub use state_sync_config::*;
mod storage_config;
pub use storage_config::*;
mod safety_rules_config;
pub use safety_rules_config::*;
mod test_config;
pub use test_config::*;
mod vm_config;
pub use vm_config::*;

/// Config pulls in configuration information from the config file.
/// This is used to set up the nodes and configure various parameters.
/// The config file is broken up into sections for each module
/// so that only that module can be passed around
#[cfg_attr(any(test, feature = "fuzzing"), derive(Clone))]
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct NodeConfig {
    #[serde(default)]
    pub admission_control: AdmissionControlConfig,
    #[serde(default)]
    pub base: Arc<BaseConfig>,
    #[serde(default)]
    pub consensus: ConsensusConfig,
    #[serde(default)]
    pub debug_interface: DebugInterfaceConfig,
    #[serde(default)]
    pub execution: ExecutionConfig,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub full_node_networks: Vec<NetworkConfig>,
    #[serde(default)]
    pub logger: LoggerConfig,
    #[serde(default)]
    pub metrics: MetricsConfig,
    #[serde(default)]
    pub mempool: MempoolConfig,
    #[serde(default)]
    pub state_sync: StateSyncConfig,
    #[serde(default)]
    pub storage: StorageConfig,
    #[serde(default)]
    pub test: Option<TestConfig>,
    #[serde(default)]
    pub validator_network: Option<NetworkConfig>,
    #[serde(default)]
    pub vm_config: VMConfig,
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct BaseConfig {
    pub data_dir: PathBuf,
    pub role: RoleType,
}

impl Default for BaseConfig {
    fn default() -> BaseConfig {
        BaseConfig {
            data_dir: PathBuf::from("."),
            role: RoleType::Validator,
        }
    }
}

impl BaseConfig {
    pub fn new(data_dir: PathBuf, role: RoleType) -> Self {
        BaseConfig { data_dir, role }
    }

    /// Returns the full path to a file path. If the file_path is relative, it prepends with the
    /// data_dir. Otherwise it returns the provided full_path.
    pub fn full_path(&self, file_path: &PathBuf) -> PathBuf {
        if file_path.is_relative() {
            self.data_dir.join(file_path)
        } else {
            file_path.clone()
        }
    }
}

#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum RoleType {
    Validator,
    FullNode,
}

impl RoleType {
    pub fn is_validator(&self) -> bool {
        *self == RoleType::Validator
    }
}

impl std::str::FromStr for RoleType {
    type Err = failure::Error;

    fn from_str(s: &str) -> Result<Self> {
        match s {
            "validator" => Ok(RoleType::Validator),
            "full_node" => Ok(RoleType::FullNode),
            _ => bail!("Invalid node role: {}", s),
        }
    }
}

impl fmt::Display for RoleType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            RoleType::Validator => write!(f, "validator"),
            RoleType::FullNode => write!(f, "full_node"),
        }
    }
}

impl NodeConfig {
    /// This clones the underlying data except for the keypair so that this config can be used as a
    /// template for another config.
    pub fn clone_for_template(&self) -> Self {
        Self {
            admission_control: self.admission_control.clone(),
            base: self.base.clone(),
            consensus: self.consensus.clone_for_template(),
            debug_interface: self.debug_interface.clone(),
            execution: self.execution.clone(),
            full_node_networks: self
                .full_node_networks
                .iter()
                .map(|c| c.clone_for_template())
                .collect(),
            logger: self.logger.clone(),
            metrics: self.metrics.clone(),
            mempool: self.mempool.clone(),
            state_sync: self.state_sync.clone(),
            storage: self.storage.clone(),
            test: None,
            validator_network: if let Some(n) = &self.validator_network {
                Some(n.clone_for_template())
            } else {
                None
            },
            vm_config: self.vm_config.clone(),
        }
    }

    pub fn set_data_dir(&mut self, path: PathBuf) -> Result<()> {
        self.base = Arc::new(BaseConfig::new(path, self.base.role));
        self.prepare()?;
        Ok(())
    }

    pub fn set_role(&mut self, role: RoleType) -> Result<()> {
        self.base = Arc::new(BaseConfig::new(self.base.data_dir.clone(), role));
        self.prepare()?;
        Ok(())
    }

    pub fn base(&self) -> &Arc<BaseConfig> {
        &self.base
    }

    fn prepare(&mut self) -> Result<()> {
        if self.base.role.is_validator() {
            ensure!(
                self.validator_network.is_some(),
                "Missing a validator network config for a validator node"
            );
        } else {
            ensure!(
                self.validator_network.is_none(),
                "Provided a validator network config for a full_node node"
            );
        }

        for network in &mut self.full_node_networks {
            network.load(self.base.clone(), RoleType::FullNode)?;
        }
        if let Some(network) = &mut self.validator_network {
            network.load(self.base.clone(), RoleType::Validator)?;
        }
        self.consensus.load(self.base.clone())?;
        self.execution.load(self.base.clone())?;
        self.metrics.load(self.base.clone())?;
        self.storage.load(self.base.clone())?;
        Ok(())
    }

    /// Reads the config file and returns the configuration object in addition to doing some
    /// post-processing of the config
    /// Paths used in the config are either absolute or relative to the config location
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
        let mut config = Self::load_config(&path);
        config.prepare()?;
        Ok(config)
    }

    pub fn save(&mut self, output_file: &PathBuf) {
        self.consensus.save();
        self.execution.save();
        if let Some(network) = &mut self.validator_network {
            network.save();
        }
        for network in &mut self.full_node_networks {
            network.save();
        }
        self.save_config(self.base.full_path(output_file));
    }

    /// Returns true if network_config is for an upstream network
    pub fn is_upstream_network(&self, network_config: &NetworkConfig) -> bool {
        self.state_sync
            .upstream_peers
            .upstream_peers
            .iter()
            .any(|peer_id| network_config.network_peers.peers.contains_key(peer_id))
    }

    pub fn randomize_ports(&mut self) {
        self.admission_control.randomize_ports();
        self.debug_interface.randomize_ports();
        self.execution.randomize_ports();
        self.mempool.randomize_ports();
        self.storage.randomize_ports();
    }

    pub fn random() -> Self {
        let mut rng = StdRng::from_seed([0u8; 32]);
        Self::random_with_rng(&mut rng)
    }

    pub fn random_with_rng(rng: &mut StdRng) -> Self {
        let mut config = NodeConfig::default();
        config.random_internal(rng);
        config
    }

    pub fn random_with_template(template: &Self, rng: &mut StdRng) -> Self {
        let mut config = template.clone_for_template();
        config.random_internal(rng);
        config
    }

    fn random_internal(&mut self, rng: &mut StdRng) {
        let mut test = TestConfig::new_with_temp_dir();

        if self.base.role == RoleType::Validator {
            test.random(rng);
            let peer_id =
                PeerId::from_public_key(test.account_keypair.as_ref().unwrap().public().unwrap());

            if self.validator_network.is_none() {
                self.validator_network = Some(NetworkConfig::default());
            }

            let validator_network = self.validator_network.as_mut().unwrap();
            validator_network.random_with_peer_id(rng, Some(peer_id));
            self.consensus.random(rng, peer_id);
        } else {
            self.validator_network = None;
            if self.full_node_networks.is_empty() {
                self.full_node_networks.push(NetworkConfig::default());
            }
            for network in &mut self.full_node_networks {
                network.random(rng);
            }
        }

        self.set_data_dir(test.temp_dir().as_ref().unwrap().into())
            .expect("Error setting data_dir");
        self.test = Some(test);
    }
}

pub trait PersistableConfig: Serialize + DeserializeOwned {
    // TODO: Return Result<Self> instead of panic.
    fn load_config<P: AsRef<Path>>(path: P) -> Self {
        let path = path.as_ref();
        let mut file =
            File::open(path).unwrap_or_else(|_| panic!("Cannot open config file {:?}", path));
        let mut contents = String::new();
        file.read_to_string(&mut contents)
            .unwrap_or_else(|_| panic!("Error reading config file {:?}", path));
        Self::parse(&contents).expect("Unable to parse config")
    }

    fn save_config<P: AsRef<Path>>(&self, output_file: P) {
        let contents = toml::to_vec(&self).expect("Error serializing");
        let mut file = File::create(output_file).expect("Error opening file");
        file.write_all(&contents).expect("Error writing file");
    }

    fn parse(serialized: &str) -> Result<Self> {
        Ok(toml::from_str(&serialized)?)
    }
}

impl<T: ?Sized> PersistableConfig for T where T: Serialize + DeserializeOwned {}

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

    static EXPECTED_SINGLE_NODE_CONFIG: &[u8] =
        include_bytes!("../../data/configs/single.node.config.toml");

    #[test]
    fn verify_test_config() {
        // This test likely failed because there was a breaking change in the NodeConfig. It may be
        // desirable to reverse the change or to change the test config and potentially documentation.
        let mut actual = NodeConfig::random();
        let mut expected = NodeConfig::parse(&String::from_utf8_lossy(EXPECTED_SINGLE_NODE_CONFIG))
            .expect("Error parsing expected single node config");

        // These are randomly generated, so let's force them to be the same, perhaps we can use a
        // random seed so that these can be made uniform...
        expected
            .set_data_dir(actual.base.data_dir.clone())
            .expect("Unable to set data_dir");
        expected.consensus.consensus_keypair = actual.consensus.consensus_keypair.clone();
        expected.consensus.consensus_peers = actual.consensus.consensus_peers.clone();

        let actual_network = actual
            .validator_network
            .as_mut()
            .expect("Missing actual network config");
        let expected_network = expected
            .validator_network
            .as_mut()
            .expect("Missing expected network config");

        expected_network.advertised_address = actual_network.advertised_address.clone();
        expected_network.listen_address = actual_network.listen_address.clone();
        expected_network.network_keypairs = actual_network.network_keypairs.clone();
        expected_network.network_peers = actual_network.network_peers.clone();
        expected_network.seed_peers = actual_network.seed_peers.clone();

        // This is broken down first into smaller evaluations to improve idenitfying what is broken.
        // The output for a broken config leveraging assert at the top level config is not readable.
        assert_eq!(actual.admission_control, expected.admission_control);
        assert_eq!(actual.base, expected.base);
        assert_eq!(actual.consensus, expected.consensus);
        assert_eq!(actual.debug_interface, expected.debug_interface);
        assert_eq!(actual.execution, expected.execution);
        assert_eq!(actual.full_node_networks, expected.full_node_networks);
        assert_eq!(actual.full_node_networks.len(), 0);
        assert_eq!(actual.logger, expected.logger);
        assert_eq!(actual.mempool, expected.mempool);
        assert_eq!(actual.metrics, expected.metrics);
        assert_eq!(actual.state_sync, expected.state_sync);
        assert_eq!(actual.storage, expected.storage);
        assert_eq!(actual.test, expected.test);
        assert_eq!(actual.validator_network, expected.validator_network);
        assert_eq!(actual.vm_config, expected.vm_config);
        assert_eq!(actual, expected);
    }

    #[test]
    fn verify_all_configs() {
        let _ = vec![
            PathBuf::from("data/configs/overrides/persistent_data.node.config.override.toml"),
            PathBuf::from("data/configs/single.node.config.toml"),
            PathBuf::from("../terraform/validator-sets/100/fn/node.config.toml"),
            PathBuf::from("../terraform/validator-sets/100/val/node.config.toml"),
            PathBuf::from("../terraform/validator-sets/dev/fn/node.config.toml"),
            PathBuf::from("../terraform/validator-sets/dev/val/node.config.toml"),
        ]
        .iter()
        .map(|path| NodeConfig::load(path).expect("NodeConfig"));
    }
}
<commit_msg>[config] Improve Parse Error<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use failure::prelude::*;
use libra_types::PeerId;
use rand::{rngs::StdRng, SeedableRng};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{
    fmt,
    fs::File,
    io::{Read, Write},
    path::{Path, PathBuf},
    sync::Arc,
};
use toml;

mod admission_control_config;
pub use admission_control_config::*;
mod consensus_config;
pub use consensus_config::*;
mod debug_interface_config;
pub use debug_interface_config::*;
mod execution_config;
pub use execution_config::*;
mod logger_config;
pub use logger_config::*;
mod metrics_config;
pub use metrics_config::*;
mod mempool_config;
pub use mempool_config::*;
mod network_config;
pub use network_config::*;
mod state_sync_config;
pub use state_sync_config::*;
mod storage_config;
pub use storage_config::*;
mod safety_rules_config;
pub use safety_rules_config::*;
mod test_config;
pub use test_config::*;
mod vm_config;
pub use vm_config::*;

/// Config pulls in configuration information from the config file.
/// This is used to set up the nodes and configure various parameters.
/// The config file is broken up into sections for each module
/// so that only that module can be passed around
#[cfg_attr(any(test, feature = "fuzzing"), derive(Clone))]
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct NodeConfig {
    #[serde(default)]
    pub admission_control: AdmissionControlConfig,
    #[serde(default)]
    pub base: Arc<BaseConfig>,
    #[serde(default)]
    pub consensus: ConsensusConfig,
    #[serde(default)]
    pub debug_interface: DebugInterfaceConfig,
    #[serde(default)]
    pub execution: ExecutionConfig,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub full_node_networks: Vec<NetworkConfig>,
    #[serde(default)]
    pub logger: LoggerConfig,
    #[serde(default)]
    pub metrics: MetricsConfig,
    #[serde(default)]
    pub mempool: MempoolConfig,
    #[serde(default)]
    pub state_sync: StateSyncConfig,
    #[serde(default)]
    pub storage: StorageConfig,
    #[serde(default)]
    pub test: Option<TestConfig>,
    #[serde(default)]
    pub validator_network: Option<NetworkConfig>,
    #[serde(default)]
    pub vm_config: VMConfig,
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct BaseConfig {
    pub data_dir: PathBuf,
    pub role: RoleType,
}

impl Default for BaseConfig {
    fn default() -> BaseConfig {
        BaseConfig {
            data_dir: PathBuf::from("."),
            role: RoleType::Validator,
        }
    }
}

impl BaseConfig {
    pub fn new(data_dir: PathBuf, role: RoleType) -> Self {
        BaseConfig { data_dir, role }
    }

    /// Returns the full path to a file path. If the file_path is relative, it prepends with the
    /// data_dir. Otherwise it returns the provided full_path.
    pub fn full_path(&self, file_path: &PathBuf) -> PathBuf {
        if file_path.is_relative() {
            self.data_dir.join(file_path)
        } else {
            file_path.clone()
        }
    }
}

#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum RoleType {
    Validator,
    FullNode,
}

impl RoleType {
    pub fn is_validator(&self) -> bool {
        *self == RoleType::Validator
    }
}

impl std::str::FromStr for RoleType {
    type Err = ParseRoleError;

    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        match s {
            "validator" => Ok(RoleType::Validator),
            "full_node" => Ok(RoleType::FullNode),
            _ => Err(ParseRoleError(s.to_string())),
        }
    }
}

impl fmt::Display for RoleType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            RoleType::Validator => write!(f, "validator"),
            RoleType::FullNode => write!(f, "full_node"),
        }
    }
}

#[derive(Debug)]
pub struct ParseRoleError(String);

impl fmt::Display for ParseRoleError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "Invalid node role: {}", &self.0)
    }
}

impl NodeConfig {
    /// This clones the underlying data except for the keypair so that this config can be used as a
    /// template for another config.
    pub fn clone_for_template(&self) -> Self {
        Self {
            admission_control: self.admission_control.clone(),
            base: self.base.clone(),
            consensus: self.consensus.clone_for_template(),
            debug_interface: self.debug_interface.clone(),
            execution: self.execution.clone(),
            full_node_networks: self
                .full_node_networks
                .iter()
                .map(|c| c.clone_for_template())
                .collect(),
            logger: self.logger.clone(),
            metrics: self.metrics.clone(),
            mempool: self.mempool.clone(),
            state_sync: self.state_sync.clone(),
            storage: self.storage.clone(),
            test: None,
            validator_network: if let Some(n) = &self.validator_network {
                Some(n.clone_for_template())
            } else {
                None
            },
            vm_config: self.vm_config.clone(),
        }
    }

    pub fn set_data_dir(&mut self, path: PathBuf) -> Result<()> {
        self.base = Arc::new(BaseConfig::new(path, self.base.role));
        self.prepare()?;
        Ok(())
    }

    pub fn set_role(&mut self, role: RoleType) -> Result<()> {
        self.base = Arc::new(BaseConfig::new(self.base.data_dir.clone(), role));
        self.prepare()?;
        Ok(())
    }

    pub fn base(&self) -> &Arc<BaseConfig> {
        &self.base
    }

    fn prepare(&mut self) -> Result<()> {
        if self.base.role.is_validator() {
            ensure!(
                self.validator_network.is_some(),
                "Missing a validator network config for a validator node"
            );
        } else {
            ensure!(
                self.validator_network.is_none(),
                "Provided a validator network config for a full_node node"
            );
        }

        for network in &mut self.full_node_networks {
            network.load(self.base.clone(), RoleType::FullNode)?;
        }
        if let Some(network) = &mut self.validator_network {
            network.load(self.base.clone(), RoleType::Validator)?;
        }
        self.consensus.load(self.base.clone())?;
        self.execution.load(self.base.clone())?;
        self.metrics.load(self.base.clone())?;
        self.storage.load(self.base.clone())?;
        Ok(())
    }

    /// Reads the config file and returns the configuration object in addition to doing some
    /// post-processing of the config
    /// Paths used in the config are either absolute or relative to the config location
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
        let mut config = Self::load_config(&path);
        config.prepare()?;
        Ok(config)
    }

    pub fn save(&mut self, output_file: &PathBuf) {
        self.consensus.save();
        self.execution.save();
        if let Some(network) = &mut self.validator_network {
            network.save();
        }
        for network in &mut self.full_node_networks {
            network.save();
        }
        self.save_config(self.base.full_path(output_file));
    }

    /// Returns true if network_config is for an upstream network
    pub fn is_upstream_network(&self, network_config: &NetworkConfig) -> bool {
        self.state_sync
            .upstream_peers
            .upstream_peers
            .iter()
            .any(|peer_id| network_config.network_peers.peers.contains_key(peer_id))
    }

    pub fn randomize_ports(&mut self) {
        self.admission_control.randomize_ports();
        self.debug_interface.randomize_ports();
        self.execution.randomize_ports();
        self.mempool.randomize_ports();
        self.storage.randomize_ports();
    }

    pub fn random() -> Self {
        let mut rng = StdRng::from_seed([0u8; 32]);
        Self::random_with_rng(&mut rng)
    }

    pub fn random_with_rng(rng: &mut StdRng) -> Self {
        let mut config = NodeConfig::default();
        config.random_internal(rng);
        config
    }

    pub fn random_with_template(template: &Self, rng: &mut StdRng) -> Self {
        let mut config = template.clone_for_template();
        config.random_internal(rng);
        config
    }

    fn random_internal(&mut self, rng: &mut StdRng) {
        let mut test = TestConfig::new_with_temp_dir();

        if self.base.role == RoleType::Validator {
            test.random(rng);
            let peer_id =
                PeerId::from_public_key(test.account_keypair.as_ref().unwrap().public().unwrap());

            if self.validator_network.is_none() {
                self.validator_network = Some(NetworkConfig::default());
            }

            let validator_network = self.validator_network.as_mut().unwrap();
            validator_network.random_with_peer_id(rng, Some(peer_id));
            self.consensus.random(rng, peer_id);
        } else {
            self.validator_network = None;
            if self.full_node_networks.is_empty() {
                self.full_node_networks.push(NetworkConfig::default());
            }
            for network in &mut self.full_node_networks {
                network.random(rng);
            }
        }

        self.set_data_dir(test.temp_dir().as_ref().unwrap().into())
            .expect("Error setting data_dir");
        self.test = Some(test);
    }
}

pub trait PersistableConfig: Serialize + DeserializeOwned {
    // TODO: Return Result<Self> instead of panic.
    fn load_config<P: AsRef<Path>>(path: P) -> Self {
        let path = path.as_ref();
        let mut file =
            File::open(path).unwrap_or_else(|_| panic!("Cannot open config file {:?}", path));
        let mut contents = String::new();
        file.read_to_string(&mut contents)
            .unwrap_or_else(|_| panic!("Error reading config file {:?}", path));
        Self::parse(&contents).expect("Unable to parse config")
    }

    fn save_config<P: AsRef<Path>>(&self, output_file: P) {
        let contents = toml::to_vec(&self).expect("Error serializing");
        let mut file = File::create(output_file).expect("Error opening file");
        file.write_all(&contents).expect("Error writing file");
    }

    fn parse(serialized: &str) -> Result<Self> {
        Ok(toml::from_str(&serialized)?)
    }
}

impl<T: ?Sized> PersistableConfig for T where T: Serialize + DeserializeOwned {}

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

    static EXPECTED_SINGLE_NODE_CONFIG: &[u8] =
        include_bytes!("../../data/configs/single.node.config.toml");

    #[test]
    fn verify_test_config() {
        // This test likely failed because there was a breaking change in the NodeConfig. It may be
        // desirable to reverse the change or to change the test config and potentially documentation.
        let mut actual = NodeConfig::random();
        let mut expected = NodeConfig::parse(&String::from_utf8_lossy(EXPECTED_SINGLE_NODE_CONFIG))
            .expect("Error parsing expected single node config");

        // These are randomly generated, so let's force them to be the same, perhaps we can use a
        // random seed so that these can be made uniform...
        expected
            .set_data_dir(actual.base.data_dir.clone())
            .expect("Unable to set data_dir");
        expected.consensus.consensus_keypair = actual.consensus.consensus_keypair.clone();
        expected.consensus.consensus_peers = actual.consensus.consensus_peers.clone();

        let actual_network = actual
            .validator_network
            .as_mut()
            .expect("Missing actual network config");
        let expected_network = expected
            .validator_network
            .as_mut()
            .expect("Missing expected network config");

        expected_network.advertised_address = actual_network.advertised_address.clone();
        expected_network.listen_address = actual_network.listen_address.clone();
        expected_network.network_keypairs = actual_network.network_keypairs.clone();
        expected_network.network_peers = actual_network.network_peers.clone();
        expected_network.seed_peers = actual_network.seed_peers.clone();

        // This is broken down first into smaller evaluations to improve idenitfying what is broken.
        // The output for a broken config leveraging assert at the top level config is not readable.
        assert_eq!(actual.admission_control, expected.admission_control);
        assert_eq!(actual.base, expected.base);
        assert_eq!(actual.consensus, expected.consensus);
        assert_eq!(actual.debug_interface, expected.debug_interface);
        assert_eq!(actual.execution, expected.execution);
        assert_eq!(actual.full_node_networks, expected.full_node_networks);
        assert_eq!(actual.full_node_networks.len(), 0);
        assert_eq!(actual.logger, expected.logger);
        assert_eq!(actual.mempool, expected.mempool);
        assert_eq!(actual.metrics, expected.metrics);
        assert_eq!(actual.state_sync, expected.state_sync);
        assert_eq!(actual.storage, expected.storage);
        assert_eq!(actual.test, expected.test);
        assert_eq!(actual.validator_network, expected.validator_network);
        assert_eq!(actual.vm_config, expected.vm_config);
        assert_eq!(actual, expected);
    }

    #[test]
    fn verify_all_configs() {
        let _ = vec![
            PathBuf::from("data/configs/overrides/persistent_data.node.config.override.toml"),
            PathBuf::from("data/configs/single.node.config.toml"),
            PathBuf::from("../terraform/validator-sets/100/fn/node.config.toml"),
            PathBuf::from("../terraform/validator-sets/100/val/node.config.toml"),
            PathBuf::from("../terraform/validator-sets/dev/fn/node.config.toml"),
            PathBuf::from("../terraform/validator-sets/dev/val/node.config.toml"),
        ]
        .iter()
        .map(|path| NodeConfig::load(path).expect("NodeConfig"));
    }
}
<|endoftext|>


<commit_before>use sass::output_style::SassOutputStyle;
use token::{Lexeme, Token};
use ast::number_value::NumberValue;
use context::Context;
use error::{Result, SassError, ErrorKind};

#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
    List(Vec<Expression>),
    Number(NumberValue),
    String(Lexeme),
}

impl Expression {
    #[allow(unused_variables)]
    pub fn to_string(&self, style: SassOutputStyle) -> String {
        match *self {
            Expression::List(ref elements) => {
                elements.iter().map(|e|
                    e.to_string(style)
                ).collect::<Vec<_>>().join(" ")
            },
            Expression::Number(ref nv) => nv.to_string(),
            Expression::String(ref lex) => lex.token.to_string(),
        }
    }

    pub fn parse<T: Iterator<Item = Result<Lexeme>>>(tokenizer: &mut T) -> Result<Expression> {
        let mut list = vec![];
        while let Some(Ok(lexeme)) = tokenizer.next() {
            if lexeme.token == Token::Semicolon {
                if list.len() == 1 {
                    return Ok(list.pop().unwrap())
                } else {
                    return Ok(Expression::List(list))
                }
            } else if let Token::Number(_, _) = lexeme.token {
                list.push(Expression::Number(NumberValue::from_scalar(lexeme)))
            } else {
                list.push(Expression::String(lexeme));
            }
        }

        let error_offset = match list.pop() {
            Some(Expression::String(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Number(nv)) => nv.offset().unwrap_or(0),
            Some(Expression::List(_)) => unreachable!(), // for now until nested lists
            None => 0,
        };
        Err(SassError {
            offset: error_offset,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected semicolon while parsing a value expression; reached EOF instead."
            ),
        })
    }

    pub fn evaluate(self, context: &Context) -> Expression {
        match self {
            Expression::List(exprs) => {
                Expression::List(exprs.into_iter().map(|e| e.evaluate(&context)).collect())
            },
            Expression::Number(nv) => Expression::Number(nv),
            Expression::String(lex) => {
                context.get_variable(&lex).unwrap_or(Expression::String(lex))
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::{Lexeme, Token};
    use ast::number_value::NumberValue;

    fn semicolon() -> Lexeme {
        Lexeme { token: Token::Semicolon, offset: None }
    }

    fn blue() -> Lexeme {
        Lexeme { token: Token::String("blue".into()), offset: None }
    }

    fn one() -> Lexeme {
        Lexeme { token: Token::Number(1.0, None), offset: None }
    }

    fn one_px() -> Lexeme {
        Lexeme { token: Token::Number(1.0, Some("px".into())), offset: None }
    }

    #[test]
    fn it_parses_a_single_string() {
        let mut fake_tokenizer = vec![Ok(blue()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::String(blue()))
        );
    }

    #[test]
    fn it_parses_a_list() {
        let mut fake_tokenizer = vec![Ok(one()), Ok(one()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::List(vec![
                Expression::Number(NumberValue::from_scalar(one())),
                Expression::Number(NumberValue::from_scalar(one())),
            ]))
        );
    }

    #[test]
    fn it_parses_a_number_without_units() {
        let mut fake_tokenizer = vec![Ok(one()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one())))
        );
    }

    #[test]
    fn it_parses_a_number_with_units() {
        let mut fake_tokenizer = vec![Ok(one_px()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one_px())))
        );
    }
}<commit_msg>Operators are not Strings<commit_after>use sass::output_style::SassOutputStyle;
use token::{Lexeme, Token};
use ast::number_value::NumberValue;
use context::Context;
use error::{Result, SassError, ErrorKind};

#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
    List(Vec<Expression>),
    Number(NumberValue),
    Operator(Lexeme),
    String(Lexeme),
}

impl Expression {
    #[allow(unused_variables)]
    pub fn to_string(&self, style: SassOutputStyle) -> String {
        match *self {
            Expression::List(ref elements) => {
                elements.iter().map(|e|
                    e.to_string(style)
                ).collect::<Vec<_>>().join(" ")
            },
            Expression::Number(ref nv) => nv.to_string(),
            Expression::Operator(ref lex) => lex.token.to_string(),
            Expression::String(ref lex) => lex.token.to_string(),
        }
    }

    pub fn parse<T: Iterator<Item = Result<Lexeme>>>(tokenizer: &mut T) -> Result<Expression> {
        let mut list = vec![];
        while let Some(Ok(lexeme)) = tokenizer.next() {
            match lexeme.token {
                Token::Semicolon => {
                    if list.len() == 1 {
                        return Ok(list.pop().unwrap())
                    } else {
                        return Ok(Expression::List(list))
                    }
                },
                Token::Number(_, _) => {
                    list.push(Expression::Number(NumberValue::from_scalar(lexeme)));
                },
                Token::Plus | Token::Minus | Token::Star | Token::Slash | Token::Percent => {
                    list.push(Expression::Operator(lexeme));
                },
                _ => {
                    list.push(Expression::String(lexeme));
                }
            }
        }

        let error_offset = match list.pop() {
            Some(Expression::String(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Operator(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Number(nv)) => nv.offset().unwrap_or(0),
            Some(Expression::List(_)) => unreachable!(), // for now until nested lists
            None => 0,
        };
        Err(SassError {
            offset: error_offset,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected semicolon while parsing a value expression; reached EOF instead."
            ),
        })
    }

    pub fn evaluate(self, context: &Context) -> Expression {
        match self {
            Expression::List(exprs) => {
                Expression::List(exprs.into_iter().map(|e| e.evaluate(&context)).collect())
            },
            Expression::Number(nv) => Expression::Number(nv),
            Expression::Operator(op) => Expression::Operator(op),
            Expression::String(lex) => {
                context.get_variable(&lex).unwrap_or(Expression::String(lex))
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::{Lexeme, Token};
    use ast::number_value::NumberValue;

    fn semicolon() -> Lexeme {
        Lexeme { token: Token::Semicolon, offset: None }
    }

    fn blue() -> Lexeme {
        Lexeme { token: Token::String("blue".into()), offset: None }
    }

    fn plus() -> Lexeme {
        Lexeme { token: Token::Plus, offset: None }
    }

    fn one() -> Lexeme {
        Lexeme { token: Token::Number(1.0, None), offset: None }
    }

    fn one_px() -> Lexeme {
        Lexeme { token: Token::Number(1.0, Some("px".into())), offset: None }
    }

    #[test]
    fn it_parses_a_single_string() {
        let mut fake_tokenizer = vec![Ok(blue()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::String(blue()))
        );
    }

    #[test]
    fn it_parses_a_list() {
        let mut fake_tokenizer = vec![
            Ok(one()),
            Ok(plus()),
            Ok(one()),
            Ok(semicolon())
        ].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::List(vec![
                Expression::Number(NumberValue::from_scalar(one())),
                Expression::Operator(plus()),
                Expression::Number(NumberValue::from_scalar(one())),
            ]))
        );
    }

    #[test]
    fn it_parses_a_number_without_units() {
        let mut fake_tokenizer = vec![Ok(one()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one())))
        );
    }

    #[test]
    fn it_parses_a_number_with_units() {
        let mut fake_tokenizer = vec![Ok(one_px()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one_px())))
        );
    }
}<|endoftext|>


<commit_before>use codespan::CodeMap;
use std::{fmt, io};
use termcolor::{Color, ColorSpec, WriteColor};

use {Diagnostic, LabelStyle};

struct Pad<T>(T, usize);

impl<T: fmt::Display> fmt::Display for Pad<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for _ in 0..(self.1) {
            self.0.fmt(f)?;
        }
        Ok(())
    }
}

pub fn emit<W>(mut writer: W, codemap: &CodeMap, diagnostic: &Diagnostic) -> io::Result<()>
where
    W: WriteColor,
{
    let supports_color = writer.supports_color();
    let line_location_color = ColorSpec::new()
        // Blue is really difficult to see on the standard windows command line
        .set_fg(Some(if cfg!(windows) { Color::Cyan } else { Color::Blue }))
        .clone();
    let diagnostic_color = ColorSpec::new()
        .set_fg(Some(diagnostic.severity.color()))
        .clone();

    let highlight_color = ColorSpec::new().set_bold(true).set_intense(true).clone();

    writer.set_color(&diagnostic_color)?;
    write!(writer, "{}", diagnostic.severity)?;
    writer.reset()?;
    write!(writer, ":")?;
    writer.set_color(&highlight_color)?;
    writeln!(writer, " {}", diagnostic.message)?;
    writer.reset()?;

    for label in &diagnostic.labels {
        match codemap.find_file(label.span.start()) {
            None => if let Some(ref message) = label.message {
                writeln!(writer, "- {}", message)?
            },
            Some(file) => {
                let (line, column) = file.location(label.span.start()).expect("location");
                writeln!(
                    writer,
                    "- {file}:{line}:{column}",
                    file = file.name(),
                    line = line.number(),
                    column = column.number(),
                )?;

                let line_span = file.line_span(line).expect("line_span");

                let line_prefix = file.src_slice(line_span.with_end(label.span.start()))
                    .expect("line_prefix");
                let line_marked = file.src_slice(label.span).expect("line_marked");
                let line_suffix = file.src_slice(line_span.with_start(label.span.end()))
                    .expect("line_suffix")
                    .trim_right_matches(|ch: char| ch == '\r' || ch == '\n');

                let mark = match label.style {
                    LabelStyle::Primary => '^',
                    LabelStyle::Secondary => '-',
                };
                let label_color = match label.style {
                    LabelStyle::Primary => diagnostic_color.clone(),
                    LabelStyle::Secondary => ColorSpec::new()
                        .set_fg(Some(if cfg!(windows) {
                            Color::Cyan
                        } else {
                            Color::Blue
                        }))
                        .clone(),
                };

                writer.set_color(&line_location_color)?;
                let line_string = line.number().to_string();
                let line_location_prefix = format!("{} | ", Pad(' ', line_string.len()));
                write!(writer, "{} | ", line_string)?;
                writer.reset()?;

                write!(writer, "{}", line_prefix)?;
                writer.set_color(&label_color)?;
                write!(writer, "{}", line_marked)?;
                writer.reset()?;
                writeln!(writer, "{}", line_suffix)?;

                if !supports_color || label.message.is_some() {
                    writer.set_color(&line_location_color)?;
                    write!(writer, "{}", line_location_prefix)?;
                    writer.reset()?;

                    writer.set_color(&label_color)?;
                    write!(
                        writer,
                        "{}{}",
                        Pad(' ', line_prefix.len()),
                        Pad(mark, line_marked.len()),
                    )?;
                    writer.reset()?;

                    if label.message.is_none() {
                        writeln!(writer)?;
                    }
                }

                match label.message {
                    None => (),
                    Some(ref label) => {
                        writer.set_color(&label_color)?;
                        writeln!(writer, " {}", label)?;
                        writer.reset()?;
                    }
                }
            }
        }
    }
    Ok(())
}
<commit_msg>Make the diagnostic severity bold and intense<commit_after>use codespan::CodeMap;
use std::{fmt, io};
use termcolor::{Color, ColorSpec, WriteColor};

use {Diagnostic, LabelStyle};

struct Pad<T>(T, usize);

impl<T: fmt::Display> fmt::Display for Pad<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for _ in 0..(self.1) {
            self.0.fmt(f)?;
        }
        Ok(())
    }
}

pub fn emit<W>(mut writer: W, codemap: &CodeMap, diagnostic: &Diagnostic) -> io::Result<()>
where
    W: WriteColor,
{
    let supports_color = writer.supports_color();
    let line_location_color = ColorSpec::new()
        // Blue is really difficult to see on the standard windows command line
        .set_fg(Some(if cfg!(windows) { Color::Cyan } else { Color::Blue }))
        .clone();
    let diagnostic_color = ColorSpec::new()
        .set_fg(Some(diagnostic.severity.color()))
        .clone();

    let highlight_color = ColorSpec::new().set_bold(true).set_intense(true).clone();

    writer.set_color(&highlight_color
        .clone()
        .set_fg(Some(diagnostic.severity.color())))?;
    write!(writer, "{}", diagnostic.severity)?;
    writer.set_color(&highlight_color)?;
    writeln!(writer, ": {}", diagnostic.message)?;
    writer.reset()?;

    for label in &diagnostic.labels {
        match codemap.find_file(label.span.start()) {
            None => if let Some(ref message) = label.message {
                writeln!(writer, "- {}", message)?
            },
            Some(file) => {
                let (line, column) = file.location(label.span.start()).expect("location");
                writeln!(
                    writer,
                    "- {file}:{line}:{column}",
                    file = file.name(),
                    line = line.number(),
                    column = column.number(),
                )?;

                let line_span = file.line_span(line).expect("line_span");

                let line_prefix = file.src_slice(line_span.with_end(label.span.start()))
                    .expect("line_prefix");
                let line_marked = file.src_slice(label.span).expect("line_marked");
                let line_suffix = file.src_slice(line_span.with_start(label.span.end()))
                    .expect("line_suffix")
                    .trim_right_matches(|ch: char| ch == '\r' || ch == '\n');

                let mark = match label.style {
                    LabelStyle::Primary => '^',
                    LabelStyle::Secondary => '-',
                };
                let label_color = match label.style {
                    LabelStyle::Primary => diagnostic_color.clone(),
                    LabelStyle::Secondary => ColorSpec::new()
                        .set_fg(Some(if cfg!(windows) {
                            Color::Cyan
                        } else {
                            Color::Blue
                        }))
                        .clone(),
                };

                writer.set_color(&line_location_color)?;
                let line_string = line.number().to_string();
                let line_location_prefix = format!("{} | ", Pad(' ', line_string.len()));
                write!(writer, "{} | ", line_string)?;
                writer.reset()?;

                write!(writer, "{}", line_prefix)?;
                writer.set_color(&label_color)?;
                write!(writer, "{}", line_marked)?;
                writer.reset()?;
                writeln!(writer, "{}", line_suffix)?;

                if !supports_color || label.message.is_some() {
                    writer.set_color(&line_location_color)?;
                    write!(writer, "{}", line_location_prefix)?;
                    writer.reset()?;

                    writer.set_color(&label_color)?;
                    write!(
                        writer,
                        "{}{}",
                        Pad(' ', line_prefix.len()),
                        Pad(mark, line_marked.len()),
                    )?;
                    writer.reset()?;

                    if label.message.is_none() {
                        writeln!(writer)?;
                    }
                }

                match label.message {
                    None => (),
                    Some(ref label) => {
                        writer.set_color(&label_color)?;
                        writeln!(writer, " {}", label)?;
                        writer.reset()?;
                    }
                }
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>//! TODO Fill in

use std::fmt::{self, Display, Formatter};
use std::default::Default;
use std::rc::Rc;
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use super::object::{Object, Objectable};
use super::class::{self, Class, ClassBuilder};

#[derive(Clone, Debug)]
pub struct ScreenState {
    // TODO Fill in
    dummy: i32
}

pub struct Screen<'lua>(Table<'lua>);

impl Default for ScreenState {
    fn default() -> Self {
        ScreenState {
            dummy: 0
        }
    }
}

impl <'lua> Screen<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "screen")?;
        Ok(Screen::allocate(lua, class)?.build())
    }
}

impl Display for ScreenState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Screen: {:p}", self)
    }
}

impl <'lua> ToLua<'lua> for Screen<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl UserData for ScreenState {}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    method_setup(lua, Class::builder(lua, Some(Rc::new(Screen::new)), None, None)?)?
        .save_class("screen")?
        .build()
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy))?
           .method("__call".into(), lua.create_function(dummy))
}

impl_objectable!(Screen, ScreenState);
<commit_msg>Stubbed out screen functions, not working yet...<commit_after>//! TODO Fill in

use std::fmt::{self, Display, Formatter};
use std::default::Default;
use std::rc::Rc;
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use super::object::{Object, Objectable, ObjectBuilder};
use super::property::Property;
use super::class::{self, Class, ClassBuilder};

#[derive(Clone, Debug)]
pub struct ScreenState {
    // TODO Fill in
    dummy: i32
}

pub struct Screen<'lua>(Table<'lua>);

impl_objectable!(Screen, ScreenState);

impl Display for ScreenState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Screen: {:p}", self)
    }
}

impl <'lua> ToLua<'lua> for Screen<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl UserData for ScreenState {}

impl Default for ScreenState {
    fn default() -> Self {
        ScreenState {
            dummy: 0
        }
    }
}

impl <'lua> Screen<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "screen")?;
        Ok(object_setup(lua, Screen::allocate(lua, class)?)?.build())
    }
}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    method_setup(lua, Class::builder(lua, Some(Rc::new(Screen::new)), None, None)?)?
        .save_class("screen")?
        .build()
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy))?
           .method("__call".into(), lua.create_function(dummy))
}

fn object_setup<'lua>(lua: &'lua Lua, builder: ObjectBuilder<'lua>) -> rlua::Result<ObjectBuilder<'lua>> {
    let table = lua.create_table();
    // TODO Make sure I'm doing this right...
    let screen_table = Screen::new(lua)?.to_lua(lua)?;
    table.set("screen", screen_table)?;
    builder.add_to_meta(table)?
           .property(Property::new("screen".into(),
                                   // TODO
                                   Some(lua.create_function(screen_new)),
                                   Some(lua.create_function(get_visible)),
                                   Some(lua.create_function(set_visible))))
}

fn screen_new<'lua>(lua: &'lua Lua, _: ()) -> rlua::Result<()> {
    unimplemented!()
}

fn get_visible<'lua>(lua: &'lua Lua, _: ()) -> rlua::Result<()> {
    unimplemented!()
}

fn set_visible<'lua>(lua: &'lua Lua, _: ()) -> rlua::Result<()> {
    unimplemented!()
}
<|endoftext|>


<commit_before>use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};

// Not re-exported
#[doc(hidden)]
pub trait ImplementedByBitFlagsMacro {}

/// A trait that is automatically implemented for all bitflags.
///
/// It should not be implemented manually.
pub trait BitFlags: ImplementedByBitFlagsMacro {
    type Bits: Bits;

    /// Returns an empty set of flags.
    fn empty() -> Self;
    /// Returns the set containing all flags.
    fn all() -> Self;
    /// Returns the raw value of the flags currently stored.
    fn bits(&self) -> Self::Bits;
    /// Convert from underlying bit representation, unless that
    /// representation contains bits that do not correspond to a flag.
    fn from_bits(bits: Self::Bits) -> Option<Self>
    where
        Self: Sized;
    /// Convert from underlying bit representation, dropping any bits
    /// that do not correspond to flags.
    fn from_bits_truncate(bits: Self::Bits) -> Self;
    /// Convert from underlying bit representation, preserving all
    /// bits (even those not corresponding to a defined flag).
    ///
    /// # Safety
    ///
    /// The caller of the `bitflags!` macro can chose to allow or
    /// disallow extra bits for their bitflags type.
    ///
    /// The caller of `from_bits_unchecked()` has to ensure that
    /// all bits correspond to a defined flag or that extra bits
    /// are valid for this bitflags type.
    unsafe fn from_bits_unchecked(bits: Self::Bits) -> Self;
    /// Returns `true` if no flags are currently stored.
    fn is_empty(&self) -> bool;
    /// Returns `true` if all flags are currently set.
    fn is_all(&self) -> bool;
    /// Returns `true` if there are flags common to both `self` and `other`.
    fn intersects(&self, other: Self) -> bool;
    /// Returns `true` all of the flags in `other` are contained within `self`.
    fn contains(&self, other: Self) -> bool;
    /// Inserts the specified flags in-place.
    fn insert(&mut self, other: Self);
    /// Removes the specified flags in-place.
    fn remove(&mut self, other: Self);
    /// Toggles the specified flags in-place.
    fn toggle(&mut self, other: Self);
    /// Inserts or removes the specified flags depending on the passed value.
    fn set(&mut self, other: Self, value: bool);
}

pub trait Sealed {}

#[doc(hidden)]
pub trait Bits:
    Clone
    + Copy
    + BitAnd
    + BitAndAssign
    + BitOr
    + BitOrAssign
    + BitXor
    + BitXorAssign
    + Not
    + Sized
    + Sealed
{
    /// The value of `Self` where no bits are set.
    const EMPTY: Self;

    /// The value of `Self` where all bits are set.
    const SATURATED: Self;
}

macro_rules! impl_bits {
    ($($u:ty, $i:ty,)*) => {
        $(
            impl Bits for $u {
                const EMPTY: $u = 0;
                const SATURATED: $u = <$u>::MAX;
            }

            impl Bits for $i {
                const EMPTY: $i = 0;
                const SATURATED: $i = <$u>::MAX as $i;
            }

            impl Sealed for $u {}
            impl Sealed for $i {}
        )*
    }
}

impl_bits! {
    u8, i8,
    u16, i16,
    u32, i32,
    u64, i64,
    u128, i128,
}
<commit_msg>fix location of export comment<commit_after>use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};

#[doc(hidden)]
pub trait ImplementedByBitFlagsMacro {}

/// A trait that is automatically implemented for all bitflags.
///
/// It should not be implemented manually.
pub trait BitFlags: ImplementedByBitFlagsMacro {
    type Bits: Bits;

    /// Returns an empty set of flags.
    fn empty() -> Self;
    /// Returns the set containing all flags.
    fn all() -> Self;
    /// Returns the raw value of the flags currently stored.
    fn bits(&self) -> Self::Bits;
    /// Convert from underlying bit representation, unless that
    /// representation contains bits that do not correspond to a flag.
    fn from_bits(bits: Self::Bits) -> Option<Self>
    where
        Self: Sized;
    /// Convert from underlying bit representation, dropping any bits
    /// that do not correspond to flags.
    fn from_bits_truncate(bits: Self::Bits) -> Self;
    /// Convert from underlying bit representation, preserving all
    /// bits (even those not corresponding to a defined flag).
    ///
    /// # Safety
    ///
    /// The caller of the `bitflags!` macro can chose to allow or
    /// disallow extra bits for their bitflags type.
    ///
    /// The caller of `from_bits_unchecked()` has to ensure that
    /// all bits correspond to a defined flag or that extra bits
    /// are valid for this bitflags type.
    unsafe fn from_bits_unchecked(bits: Self::Bits) -> Self;
    /// Returns `true` if no flags are currently stored.
    fn is_empty(&self) -> bool;
    /// Returns `true` if all flags are currently set.
    fn is_all(&self) -> bool;
    /// Returns `true` if there are flags common to both `self` and `other`.
    fn intersects(&self, other: Self) -> bool;
    /// Returns `true` all of the flags in `other` are contained within `self`.
    fn contains(&self, other: Self) -> bool;
    /// Inserts the specified flags in-place.
    fn insert(&mut self, other: Self);
    /// Removes the specified flags in-place.
    fn remove(&mut self, other: Self);
    /// Toggles the specified flags in-place.
    fn toggle(&mut self, other: Self);
    /// Inserts or removes the specified flags depending on the passed value.
    fn set(&mut self, other: Self, value: bool);
}

// Not re-exported
pub trait Sealed {}

#[doc(hidden)]
pub trait Bits:
    Clone
    + Copy
    + BitAnd
    + BitAndAssign
    + BitOr
    + BitOrAssign
    + BitXor
    + BitXorAssign
    + Not
    + Sized
    + Sealed
{
    /// The value of `Self` where no bits are set.
    const EMPTY: Self;

    /// The value of `Self` where all bits are set.
    const SATURATED: Self;
}

macro_rules! impl_bits {
    ($($u:ty, $i:ty,)*) => {
        $(
            impl Bits for $u {
                const EMPTY: $u = 0;
                const SATURATED: $u = <$u>::MAX;
            }

            impl Bits for $i {
                const EMPTY: $i = 0;
                const SATURATED: $i = <$u>::MAX as $i;
            }

            impl Sealed for $u {}
            impl Sealed for $i {}
        )*
    }
}

impl_bits! {
    u8, i8,
    u16, i16,
    u32, i32,
    u64, i64,
    u128, i128,
}
<|endoftext|>


<commit_before>extern crate yoga;

use yoga::{Direction, FlexDirection, Node, StyleUnit, Undefined};

#[test]
fn test_copy_style_same() {
	let node0 = Node::new();
	let node1 = Node::new();
	assert!(!node0.is_dirty());

	node0.copy_style(&node1);
	assert!(!node0.is_dirty());
}

#[test]
fn test_copy_style_modified() {
	let node0 = Node::new();
	assert!(!node0.is_dirty());
	assert_eq!(FlexDirection::Column, node0.get_flex_direction());

	match node0.get_style_max_height() {
		StyleUnit::UndefinedValue => assert!(true),
		_ => assert!(false),
	}

	let mut node1 = Node::new();
	node1.set_flex_direction(FlexDirection::Row);
	node1.set_max_height(StyleUnit::Point(10.0.into()));

	node0.copy_style(&node1);
	assert!(node0.is_dirty());
	assert_eq!(FlexDirection::Row, node0.get_flex_direction());

	match node0.get_style_max_height() {
		StyleUnit::Point(value) => assert_eq!(10.0, value.into_inner()),
		_ => assert!(false),
	}
}

#[test]
fn test_copy_style_modified_same() {
	let mut node0 = Node::new();
	node0.set_flex_direction(FlexDirection::Row);
	node0.set_max_height(StyleUnit::Point(10.0.into()));
	node0.calculate_layout(Undefined, Undefined, Direction::LTR);
	assert!(!node0.is_dirty());

	let mut node1 = Node::new();
	node1.set_flex_direction(FlexDirection::Row);
	node1.set_max_height(StyleUnit::Point(10.0.into()));

	node0.copy_style(&node1);
	assert!(!node0.is_dirty());
}
<commit_msg>Address comments for `test_copy_style_modified`<commit_after>extern crate yoga;

use yoga::{Direction, FlexDirection, Node, StyleUnit, Undefined};

#[test]
fn test_copy_style_same() {
	let node0 = Node::new();
	let node1 = Node::new();
	assert!(!node0.is_dirty());

	node0.copy_style(&node1);
	assert!(!node0.is_dirty());
}

#[test]
fn test_copy_style_modified() {
	let node0 = Node::new();
	assert!(!node0.is_dirty());
	assert_eq!(FlexDirection::Column, node0.get_flex_direction());
	assert_eq!(node0.get_style_max_height(), StyleUnit::UndefinedValue);

	let mut node1 = Node::new();
	node1.set_flex_direction(FlexDirection::Row);
	node1.set_max_height(StyleUnit::Point(10.0.into()));

	node0.copy_style(&node1);
	assert!(node0.is_dirty());
	assert_eq!(FlexDirection::Row, node0.get_flex_direction());
	assert_eq!(node0.get_style_max_height(), StyleUnit::Point(10.0.into()));
}

#[test]
fn test_copy_style_modified_same() {
	let mut node0 = Node::new();
	node0.set_flex_direction(FlexDirection::Row);
	node0.set_max_height(StyleUnit::Point(10.0.into()));
	node0.calculate_layout(Undefined, Undefined, Direction::LTR);
	assert!(!node0.is_dirty());

	let mut node1 = Node::new();
	node1.set_flex_direction(FlexDirection::Row);
	node1.set_max_height(StyleUnit::Point(10.0.into()));

	node0.copy_style(&node1);
	assert!(!node0.is_dirty());
}
<|endoftext|>


<commit_before>use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
use std::fmt::{Formatter, Result, Display};
use bit_reverse::ParallelReverse;

/// Represents a 64-bit bitboard.
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct BitBoard(pub u64);

impl BitBoard {
    pub fn flip(&self) -> Self {
        BitBoard(self.0.swap_bits())
    }
}

// ---------------------------------------------------------------------------
// Operations
impl BitAnd for BitBoard {
    type Output = Self;

    fn bitand(self, rhs: Self) -> Self {
        BitBoard(self.0 & rhs.0)
    }
}

impl BitAndAssign for BitBoard {
    fn bitand_assign(&mut self, rhs: Self) {
        *self = BitBoard(self.0 & rhs.0)
    }
}

impl BitOr for BitBoard {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self {
        BitBoard(self.0 | rhs.0)
    }
}

impl BitOrAssign for BitBoard {
    fn bitor_assign(&mut self, rhs: Self) {
        *self = BitBoard(self.0 | rhs.0)
    }
}

impl BitXor for BitBoard {
    type Output = Self;

    fn bitxor(self, rhs: Self) -> Self {
        BitBoard(self.0 ^ rhs.0)
    }
}

impl BitXorAssign for BitBoard {
    fn bitxor_assign(&mut self, rhs: Self) {
        *self = BitBoard(self.0 ^ rhs.0)
    }
}

impl Not for BitBoard {
    type Output = Self;

    fn not(self) -> Self {
        BitBoard(!self.0)
    }
}

// ---------------------------------------------------------------------------
// Display
impl Display for BitBoard {
    #[allow(unused_must_use)]
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "\n{}:\n+-+-+-+-+-+-+-+-+-+\n", self.0);
        for rank in 0..8 {
            write!(f, "| ");
            for file in 0..8 {
                write!(f, "{} ", if self.0 & (1 << ((7 - rank) * 8 + file)) > 0 { "X" } else { "-" });
            }
            write!(f, "|\n");
        }
        write!(f, "+-+-+-+-+-+-+-+-+-+")
    }
}
<commit_msg>Use String rather than multiple prints in bitboard display method<commit_after>use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
use std::fmt::{Formatter, Result, Display};
use bit_reverse::ParallelReverse;

/// Represents a 64-bit bitboard.
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct BitBoard(pub u64);

impl BitBoard {
    pub fn flip(&self) -> Self {
        BitBoard(self.0.swap_bits())
    }
}

// ---------------------------------------------------------------------------
// Operations
impl BitAnd for BitBoard {
    type Output = Self;

    fn bitand(self, rhs: Self) -> Self {
        BitBoard(self.0 & rhs.0)
    }
}

impl BitAndAssign for BitBoard {
    fn bitand_assign(&mut self, rhs: Self) {
        *self = BitBoard(self.0 & rhs.0)
    }
}

impl BitOr for BitBoard {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self {
        BitBoard(self.0 | rhs.0)
    }
}

impl BitOrAssign for BitBoard {
    fn bitor_assign(&mut self, rhs: Self) {
        *self = BitBoard(self.0 | rhs.0)
    }
}

impl BitXor for BitBoard {
    type Output = Self;

    fn bitxor(self, rhs: Self) -> Self {
        BitBoard(self.0 ^ rhs.0)
    }
}

impl BitXorAssign for BitBoard {
    fn bitxor_assign(&mut self, rhs: Self) {
        *self = BitBoard(self.0 ^ rhs.0)
    }
}

impl Not for BitBoard {
    type Output = Self;

    fn not(self) -> Self {
        BitBoard(!self.0)
    }
}

// ---------------------------------------------------------------------------
// Display
impl Display for BitBoard {
    #[allow(unused_must_use)]
    fn fmt(&self, f: &mut Formatter) -> Result {
        let mut str = String::new();
        str.push_str(self.0.to_string().as_str());
        str.push_str("\n+-+-+-+-+-+-+-+-+-+\n");
        for rank in 0..8 {
            str.push_str("| ");
            for file in 0..8 {
                let char = if self.0 & (1 << ((7 - rank) * 8 + file)) > 0 {
                    "X"
                } else {
                    "-"
                };
                str.push_str(char);
            }
            str.push_str("|\n");
        }
        str.push_str("+-+-+-+-+-+-+-+-+-+");
        write!(f, "{}", str)
    }
}
<|endoftext|>


<commit_before>/// Handles focus tracking on a workspace.
/// `focus` keeps track of the focused window's id
/// and `up` and `down` are the windows above or
/// below the focus stack respectively.
#[derive(Clone, PartialEq, Eq)]
pub struct Stack<T> {
    pub focus: T,
    pub up:    Vec<T>,
    pub down:  Vec<T>
}

impl<T: Clone + Eq> Stack<T> {
    /// Create a new stack with the given values
    pub fn new(f: T, up: Vec<T>, down: Vec<T>) -> Stack<T> {
        Stack {
            focus: f,
            up:    up,
            down:  down
        }
    }

    /// Create a new stack with only the given element
    /// as the focused one and initialize the rest to empty.
    pub fn from_element(t: T) -> Stack<T> {
        Stack {
            focus: t,
            up:    Vec::new(),
            down:  Vec::new()
        }
    }

    /// Add a new element to the stack
    /// and automatically focus it.
    pub fn add(&self, t: T) -> Stack<T> {
        Stack {
            focus: t,
            up: self.up.clone(),
            down: self.down.clone() + &(vec!(self.focus.clone()))[..]
        }
    }

    /// Flatten the stack into a list
    pub fn integrate(&self) -> Vec<T> {
        self.up.iter()
            .rev()
            .chain((vec!(self.focus.clone())).iter())
            .chain(self.down.iter())
            .map(|x| x.clone())
            .collect()
    }

    /// Filter the stack to retain only windows
    /// that yield true in the given filter function
    pub fn filter<F>(&self, f: F) -> Option<Stack<T>> where F : Fn(&T) -> bool {
        let lrs : Vec<T> = (vec!(self.focus.clone()) + &self.down[..]).iter()
            .filter(|&x| f(x))
            .map(|x| x.clone())
            .collect();

        if lrs.len() > 0 {
            let first : T         = lrs[0].clone();
            let rest : Vec<T>     = lrs.iter().skip(1).map(|x| x.clone()).collect();
            let filtered : Vec<T> = self.up.iter()
                .filter(|&x| f(x))
                .map(|x| x.clone())
                .collect();
            let stack : Stack<T>  = Stack::<T>::new(first, filtered, rest);

            Some(stack)
        } else {
            let filtered : Vec<T> = self.up.iter().map(|x| x.clone()).filter(|x| f(x)).collect();
            if filtered.len() > 0 {
                let first : T        = filtered[0].clone();
                let rest : Vec<T>    = filtered.iter().skip(1).map(|x| x.clone()).collect();

                Some(Stack::<T>::new(first, rest, Vec::new()))
            } else {
                None
            }
        }
    }

    /// Move the focus to the next element in the `up` list
    pub fn focus_up(&self) -> Stack<T> {
        if self.up.is_empty() {
            let tmp : Vec<T> = (vec!(self.focus.clone()) + &self.down[..]).into_iter()
                .rev()
                .collect();
            let xs : Vec<T> = tmp.iter()
                .skip(1)
                .map(|x| x.clone())
                .collect();

            Stack::<T>::new(tmp[0].clone(), xs, Vec::new())
        } else {
            let down = (vec!(self.focus.clone())) + &self.down[..];
            let up   = self.up.iter().skip(1).map(|x| x.clone()).collect();
            Stack::<T>::new(self.up[0].clone(), up, down)
        }
    }

    /// Move the focus down
    pub fn focus_down(&self) -> Stack<T> {
        self.reverse().focus_up().reverse()
    }

    pub fn swap_up(&self) -> Stack<T> {
        if self.up.is_empty() {
            Stack::<T>::new(self.focus.clone(), self.down.iter().rev().map(|x| x.clone()).collect(), Vec::new())
        } else {
            let x = self.up[0].clone();
            let xs = self.up.iter().skip(1).map(|x| x.clone()).collect();
            let rs = vec!(x) + &self.down[..];
            Stack::<T>::new(self.focus.clone(), xs, rs)
        }
    }

    pub fn swap_down(&self) -> Stack<T> {
        self.reverse().swap_up().reverse()
    }

    pub fn swap_master(&self) -> Stack<T> {
        if self.up.is_empty() {
            return self.clone();
        }

        let r : Vec<T>  = self.up.iter()
            .rev()
            .map(|x| x.clone())
            .collect();
        let x : T       = r[0].clone();
        let xs : Vec<T> = r.iter()
            .skip(1)
            .map(|x| x.clone())
            .collect();
        let rs : Vec<T> = xs + &(vec!(x) + &self.down[..])[..];

        Stack::<T>::new(self.focus.clone(), Vec::new(), rs)
    }

    /// Reverse the stack by exchanging
    /// the `up` and `down` lists
    pub fn reverse(&self) -> Stack<T> {
        Stack::<T>::new(self.focus.clone(), self.down.clone(), self.up.clone())
    }

    /// Return the number of elements tracked by the stack
    pub fn len(&self) -> usize {
        1 + self.up.len() + self.down.len()
    }

    /// Checks if the given window is tracked by the stack
    pub fn contains(&self, window: T) -> bool {
        self.focus == window || self.up.contains(&window) || self.down.contains(&window)
    }
}
<commit_msg>replaced map(|x| x) with cloned()<commit_after>/// Handles focus tracking on a workspace.
/// `focus` keeps track of the focused window's id
/// and `up` and `down` are the windows above or
/// below the focus stack respectively.
#[derive(Clone, PartialEq, Eq)]
pub struct Stack<T> {
    pub focus: T,
    pub up:    Vec<T>,
    pub down:  Vec<T>
}

impl<T: Clone + Eq> Stack<T> {
    /// Create a new stack with the given values
    pub fn new(f: T, up: Vec<T>, down: Vec<T>) -> Stack<T> {
        Stack {
            focus: f,
            up:    up,
            down:  down
        }
    }

    /// Create a new stack with only the given element
    /// as the focused one and initialize the rest to empty.
    pub fn from_element(t: T) -> Stack<T> {
        Stack {
            focus: t,
            up:    Vec::new(),
            down:  Vec::new()
        }
    }

    /// Add a new element to the stack
    /// and automatically focus it.
    pub fn add(&self, t: T) -> Stack<T> {
        Stack {
            focus: t,
            up: self.up.clone(),
            down: self.down.clone() + &(vec!(self.focus.clone()))[..]
        }
    }

    /// Flatten the stack into a list
    pub fn integrate(&self) -> Vec<T> {
        self.up.iter()
            .rev()
            .chain((vec!(self.focus.clone())).iter())
            .chain(self.down.iter())
            .cloned()
            .collect()
    }

    /// Filter the stack to retain only windows
    /// that yield true in the given filter function
    pub fn filter<F>(&self, f: F) -> Option<Stack<T>> where F : Fn(&T) -> bool {
        let lrs : Vec<T> = (vec!(self.focus.clone()) + &self.down[..]).iter()
            .filter(|&x| f(x))
            .map(|x| x.clone())
            .collect();

        if lrs.len() > 0 {
            let first : T         = lrs[0].clone();
            let rest : Vec<T>     = lrs.iter().skip(1).map(|x| x.clone()).collect();
            let filtered : Vec<T> = self.up.iter()
                .filter(|&x| f(x))
                .cloned()
                .collect();
            let stack : Stack<T>  = Stack::<T>::new(first, filtered, rest);

            Some(stack)
        } else {
            let filtered : Vec<T> = self.up.clone().into_iter().filter(|x| f(x)).collect();
            if filtered.len() > 0 {
                let first : T        = filtered[0].clone();
                let rest : Vec<T>    = filtered.iter().skip(1).cloned().collect();
                Some(Stack::<T>::new(first, rest, Vec::new()))
            } else {
                None
            }
        }
    }

    /// Move the focus to the next element in the `up` list
    pub fn focus_up(&self) -> Stack<T> {
        if self.up.is_empty() {
            let tmp : Vec<T> = (vec!(self.focus.clone()) + &self.down[..]).into_iter()
                .rev()
                .collect();
            let xs : Vec<T> = tmp.iter()
                .skip(1)
                .cloned()
                .collect();

            Stack::<T>::new(tmp[0].clone(), xs, Vec::new())
        } else {
            let down = (vec!(self.focus.clone())) + &self.down[..];
            let up   = self.up.iter().skip(1).cloned().collect();
            Stack::<T>::new(self.up[0].clone(), up, down)
        }
    }

    /// Move the focus down
    pub fn focus_down(&self) -> Stack<T> {
        self.reverse().focus_up().reverse()
    }

    pub fn swap_up(&self) -> Stack<T> {
        if self.up.is_empty() {
            Stack::<T>::new(self.focus.clone(), self.down.iter().rev().cloned().collect(), Vec::new())
        } else {
            let x = self.up[0].clone();
            let xs = self.up.iter().skip(1).cloned().collect();
            let rs = vec!(x) + &self.down[..];
            Stack::<T>::new(self.focus.clone(), xs, rs)
        }
    }

    pub fn swap_down(&self) -> Stack<T> {
        self.reverse().swap_up().reverse()
    }

    pub fn swap_master(&self) -> Stack<T> {
        if self.up.is_empty() {
            return self.clone();
        }

        let r : Vec<T>  = self.up.iter()
            .rev()
            .map(|x| x.clone())
            .collect();
        let x : T       = r[0].clone();
        let xs : Vec<T> = r.iter()
            .skip(1)
            .map(|x| x.clone())
            .collect();
        let rs : Vec<T> = xs + &(vec!(x) + &self.down[..])[..];

        Stack::<T>::new(self.focus.clone(), Vec::new(), rs)
    }

    /// Reverse the stack by exchanging
    /// the `up` and `down` lists
    pub fn reverse(&self) -> Stack<T> {
        Stack::<T>::new(self.focus.clone(), self.down.clone(), self.up.clone())
    }

    /// Return the number of elements tracked by the stack
    pub fn len(&self) -> usize {
        1 + self.up.len() + self.down.len()
    }

    /// Checks if the given window is tracked by the stack
    pub fn contains(&self, window: T) -> bool {
        self.focus == window || self.up.contains(&window) || self.down.contains(&window)
    }
}
<|endoftext|>