<commit_before>use std::collections::HashMap;

use serde_json::Value as JsonValue;

use schema::Schema;

#[derive(Clone, Debug, PartialEq)]
pub enum Value {
    Null,
    Boolean(bool),
    Int(i32),
    Long(i64),
    Float(f32),
    Double(f64),
    Bytes(Vec<u8>),
    String(String),
    Fixed(Vec<u8>),  // TODO: remove and use Bytes?
    Union(Option<Box<Value>>),
    Array(Vec<Value>),
    Map(HashMap<String, Value>),
    Record(Schema, HashMap<String, Value>),
}

pub trait ToAvro {
    fn avro(self) -> Value;
}

macro_rules! to_avro(
    ($t:ty, $v:expr) => (
        impl ToAvro for $t {
            fn avro(self) -> Value {
                $v(self)
            }
        }
    );
);

to_avro!(bool, Value::Boolean);
to_avro!(i32, Value::Int);
to_avro!(i64, Value::Long);
to_avro!(f32, Value::Float);
to_avro!(f64, Value::Double);
to_avro!(String, Value::String);

impl<'a> ToAvro for &'a str {
    fn avro(self) -> Value {
        Value::String(self.to_owned())
    }
}

impl<'a> ToAvro for &'a [u8] {
    fn avro(self) -> Value {
        Value::Bytes(self.to_owned())
    }
}

impl<T> ToAvro for Option<T> where T: ToAvro {
    fn avro(self) -> Value {
        Value::Union(self.map(|v| Box::new(v.avro())))
    }
}

impl ToAvro for Value {
    fn avro(self) -> Value {
        self
    }
}

impl<T> ToAvro for Box<T> where T: ToAvro {
    fn avro(self) -> Value {
        (*self).avro()
    }
}

#[derive(Debug)]
pub struct Record<'a> {
    schema: &'a Schema,
    lookup: &'a HashMap<String, usize>,
    fields: HashMap<String, Value>,
}

impl<'a> Record<'a> {
    pub fn new(schema: &'a Schema) -> Option<Record<'a>> {
        match schema {
            &Schema::Record { ref fields_lookup, .. } => {
                Some(Record {
                    schema: schema,
                    lookup: fields_lookup,
                    fields: HashMap::new(),
                })
            },
            _ => None,
        }
    }

    pub fn put<V>(&mut self, field: &str, value: V) where V: ToAvro {
        if let Some(_) = self.lookup.get(field) {
            self.fields.insert(field.to_owned(), value.avro());
        }
    }
}

impl<'a> ToAvro for Record<'a> {
    fn avro(self) -> Value {
        Value::Record(self.schema.clone(), self.fields)
    }
}

impl ToAvro for JsonValue {
    fn avro(self) -> Value {
        match self {
            JsonValue::Null => Value::Null,
            JsonValue::Bool(b) => Value::Boolean(b),
            JsonValue::Number(ref n) if n.is_i64() => Value::Long(n.as_i64().unwrap()),
            JsonValue::Number(ref n) if n.is_f64() => Value::Double(n.as_f64().unwrap()),
            JsonValue::Number(n) => Value::Long(n.as_u64().unwrap() as i64),  // TODO: Not so great
            JsonValue::String(s) => Value::String(s),
            JsonValue::Array(items) =>
                Value::Array(items.into_iter()
                    .map(|item| item.avro())
                    .collect::<_>()),
            JsonValue::Object(items) =>
                Value::Map(items.into_iter()
                    .map(|(key, value)| (key, value.avro()))
                    .collect::<_>()),
        }
    }
}
<commit_msg>Add ToAvro for () and HashMaps<commit_after>use std::collections::HashMap;

use serde_json::Value as JsonValue;

use schema::Schema;

#[derive(Clone, Debug, PartialEq)]
pub enum Value {
    Null,
    Boolean(bool),
    Int(i32),
    Long(i64),
    Float(f32),
    Double(f64),
    Bytes(Vec<u8>),
    String(String),
    Fixed(Vec<u8>),  // TODO: remove and use Bytes?
    Union(Option<Box<Value>>),
    Array(Vec<Value>),
    Map(HashMap<String, Value>),
    Record(Schema, HashMap<String, Value>),
}

pub trait ToAvro {
    fn avro(self) -> Value;
}

macro_rules! to_avro(
    ($t:ty, $v:expr) => (
        impl ToAvro for $t {
            fn avro(self) -> Value {
                $v(self)
            }
        }
    );
);

to_avro!(bool, Value::Boolean);
to_avro!(i32, Value::Int);
to_avro!(i64, Value::Long);
to_avro!(f32, Value::Float);
to_avro!(f64, Value::Double);
to_avro!(String, Value::String);

impl ToAvro for () {
    fn avro(self) -> Value {
        Value::Null
    }
}

impl<'a> ToAvro for &'a str {
    fn avro(self) -> Value {
        Value::String(self.to_owned())
    }
}

impl<'a> ToAvro for &'a [u8] {
    fn avro(self) -> Value {
        Value::Bytes(self.to_owned())
    }
}

impl<T> ToAvro for Option<T> where T: ToAvro {
    fn avro(self) -> Value {
        Value::Union(self.map(|v| Box::new(v.avro())))
    }
}

impl<T> ToAvro for HashMap<String, T> where T: ToAvro {
    fn avro(self) -> Value {
        Value::Map(self
            .into_iter()
            .map(|(key, value)| (key, value.avro()))
            .collect::<_>())
    }
}

impl<'a, T> ToAvro for HashMap<&'a str, T> where T: ToAvro {
    fn avro(self) -> Value {
        Value::Map(self
            .into_iter()
            .map(|(key, value)| (key.to_owned(), value.avro()))
            .collect::<_>())
    }
}

impl ToAvro for Value {
    fn avro(self) -> Value {
        self
    }
}

impl<T> ToAvro for Box<T> where T: ToAvro {
    fn avro(self) -> Value {
        (*self).avro()
    }
}

#[derive(Debug)]
pub struct Record<'a> {
    schema: &'a Schema,
    lookup: &'a HashMap<String, usize>,
    fields: HashMap<String, Value>,
}

impl<'a> Record<'a> {
    pub fn new(schema: &'a Schema) -> Option<Record<'a>> {
        match schema {
            &Schema::Record { ref fields_lookup, .. } => {
                Some(Record {
                    schema: schema,
                    lookup: fields_lookup,
                    fields: HashMap::new(),
                })
            },
            _ => None,
        }
    }

    pub fn put<V>(&mut self, field: &str, value: V) where V: ToAvro {
        if let Some(_) = self.lookup.get(field) {
            self.fields.insert(field.to_owned(), value.avro());
        }
    }
}

impl<'a> ToAvro for Record<'a> {
    fn avro(self) -> Value {
        Value::Record(self.schema.clone(), self.fields)
    }
}

impl ToAvro for JsonValue {
    fn avro(self) -> Value {
        match self {
            JsonValue::Null => Value::Null,
            JsonValue::Bool(b) => Value::Boolean(b),
            JsonValue::Number(ref n) if n.is_i64() => Value::Long(n.as_i64().unwrap()),
            JsonValue::Number(ref n) if n.is_f64() => Value::Double(n.as_f64().unwrap()),
            JsonValue::Number(n) => Value::Long(n.as_u64().unwrap() as i64),  // TODO: Not so great
            JsonValue::String(s) => Value::String(s),
            JsonValue::Array(items) =>
                Value::Array(items.into_iter()
                    .map(|item| item.avro())
                    .collect::<_>()),
            JsonValue::Object(items) =>
                Value::Map(items.into_iter()
                    .map(|(key, value)| (key, value.avro()))
                    .collect::<_>()),
        }
    }
}
<|endoftext|>


<commit_before>//! Provides various useful utilities.
use std::io;
use std::fs;
use std::fmt;
use std::env;
use std::panic;
use std::os::unix::io::RawFd;
use std::result::Result as StdResult;
use std::io::{Read, Write};
use std::sync::Mutex;

use pbr;
use regex::Regex;
use chrono::Duration;
use serde::{Serialize, Deserialize, de, ser};

use super::{Result, ResultExt, Error, ErrorKind};

pub const SD_LISTEN_FDS_START: RawFd = 3;

/// Helper for serializing/deserializing addresses in string format
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Addr(pub u64);

/// Helper for formatting durations.
pub struct HumanDuration(pub Duration);

impl Into<u64> for Addr {
    fn into(self) -> u64 {
        self.0
    }
}

impl<'a> fmt::Display for HumanDuration {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        macro_rules! try_write {
            ($num:expr, $str:expr) => {
                if $num == 1 { return write!(f, "1 {}", $str); }
                else if $num > 1 { return write!(f, "{} {}s", $num, $str); }
            }
        }

        try_write!(self.0.num_hours(), "hour");
        try_write!(self.0.num_minutes(), "minute");
        try_write!(self.0.num_seconds(), "second");
        write!(f, "0 seconds")
    }
}

impl Serialize for Addr {
    fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
        where S: ser::Serializer
    {
        serializer.serialize_str(&format!("0x{:x}", self.0))
    }
}

impl Deserialize for Addr {
    fn deserialize<D>(deserializer: D) -> StdResult<Addr, D::Error>
        where D: de::Deserializer {
        struct AddrVisitor;

        impl de::Visitor for AddrVisitor {
            type Value = u64;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("an address")
            }

            fn visit_str<E: de::Error>(self, value: &str) -> StdResult<u64, E> {
                if &value[..2] == "0x" {
                    u64::from_str_radix(&value[2..], 16)
                        .map_err(|e| E::custom(e.to_string()))
                } else {
                    u64::from_str_radix(&value, 10)
                        .map_err(|e| E::custom(e.to_string()))
                }
            }

            fn visit_u64<E: de::Error>(self, value: u64) -> StdResult<u64, E> {
                Ok(value)
            }
        }

        deserializer.deserialize_str(AddrVisitor).map(Addr)
    }
}

#[derive(Clone, Debug, Default)]
pub struct RegexFilter {
    patterns: Vec<Regex>,
}

impl Deserialize for RegexFilter {
    fn deserialize<D>(deserializer: D) -> StdResult<RegexFilter, D::Error>
        where D: de::Deserializer {
        struct FilterVisitor;

        impl de::Visitor for FilterVisitor {
            type Value = Vec<Regex>;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a regular expression filter")
            }

            fn visit_seq<V>(self, mut visitor: V)
                -> StdResult<Vec<Regex>, V::Error>
                where V: de::SeqVisitor
            {
                let mut rv = vec![];
                while let Some(item) = visitor.visit::<String>()? {
                    rv.push(Regex::new(&item)
                        .map_err(|err| {
                            <V::Error as de::Error>::custom(format!(
                                "invalid regular expression '{}': {}", &item, err))
                        })?);
                }
                Ok(rv)
            }

            fn visit_str<E: de::Error>(self, value: &str)
                -> StdResult<Vec<Regex>, E>
            {
                Ok(vec![Regex::new(value)
                    .map_err(|err| {
                        E::custom(format!("invalid regular expression '{}': {}", value, err))
                    })?])
            }
        }

        deserializer.deserialize_seq(FilterVisitor).map(|patterns| {
            RegexFilter { patterns: patterns }
        })
    }
}

impl RegexFilter {
    pub fn matches(&self, value: &str) -> bool {
        for pattern in self.patterns.iter() {
            if pattern.is_match(value) {
                return true;
            }
        }
        false
    }
}

/// Helper that runs a function and captures panics.
///
/// The function needs to be reasonably protected against panics.  This
/// might poison mutexes and similar things.
pub fn run_isolated<F>(f: F)
    where F: FnOnce() -> Result<()>, F: Send
{
    let rv = panic::catch_unwind(panic::AssertUnwindSafe(move || {
        if let Err(err) = f() {
            use std::error::Error;
            error!("task failed: {}", &err);
            let mut cause = err.cause();
            while let Some(the_cause) = cause {
                error!("  caused by: {}", the_cause);
                cause = the_cause.cause();
            }
            if let Some(backtrace) = err.backtrace() {
                debug!("  Traceback: {:?}", backtrace);
            }
        }
    }));

    // the default panic handler will already have printed here
    if let Err(_) = rv {
        error!("task panicked!");
    }
}

/// A thread safe progress bar
pub struct ProgressIndicator {
    pb: Mutex<Option<pbr::ProgressBar<io::Stdout>>>,
}

fn make_progress_bar(count: usize) -> pbr::ProgressBar<io::Stdout> {
    let mut pb = pbr::ProgressBar::new(count as u64);
    pb.tick_format("⠇⠋⠙⠸⠴⠦");
    pb.format("[■□□]");
    pb.show_tick = true;
    pb.show_speed = false;
    pb.show_percent = false;
    pb.show_counter = false;
    pb.show_time_left = false;
    pb.message(&format!("{: <44}", ""));
    pb
}

impl ProgressIndicator {
    /// Creates a new progress bar for a given count
    pub fn new(count: usize) -> ProgressIndicator {
        ProgressIndicator {
            pb: Mutex::new(Some(make_progress_bar(count))),
        }
    }

    /// Creates a dummy progress bar that does nothing
    pub fn disabled() -> ProgressIndicator {
        ProgressIndicator {
            pb: Mutex::new(None),
        }
    }

    /// Increments the progress bar by a step counter
    pub fn inc(&self, step: usize) {
        if let Some(ref mut pb) = *self.pb.lock().unwrap() {
            pb.add(step as u64);
        }
    }

    /// Ticks the progress bar without advancing
    pub fn tick(&self) {
        if let Some(ref mut pb) = *self.pb.lock().unwrap() {
            pb.tick();
        }
    }

    /// Sets the current message
    pub fn set_message(&self, msg: &str) {
        if let Some(ref mut pb) = *self.pb.lock().unwrap() {
            pb.message(&format!("  ◦ {: <40}", msg));
            pb.tick();
        }
    }

    /// Marks the progress bar finished and replaces it with a message
    pub fn finish(&self, msg: &str) {
        if let Some(ref mut pb) = *self.pb.lock().unwrap() {
            pb.finish_print(&format!("  ● {}", msg));
            println!("");
        }
    }

    /// Finishes the current bar and adds a new one.  If the progress bar
    /// is disabled this does nothing instead.
    pub fn add_bar(&self, count: usize) {
        let mut pb = self.pb.lock().unwrap();
        if !pb.is_none() {
            *pb = Some(make_progress_bar(count));
        }
    }
}

/// Like ``io::copy`` but advances a progress bar set to bytes.
pub fn copy_with_progress<R: ?Sized, W: ?Sized>(progress: &ProgressIndicator,
                                                reader: &mut R, writer: &mut W)
    -> io::Result<u64>
    where R: Read, W: Write
{
    let mut buf = [0; 16384];
    let mut written = 0;
    loop {
        let len = match reader.read(&mut buf) {
            Ok(0) => return Ok(written),
            Ok(len) => len,
            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };
        writer.write_all(&buf[..len])?;
        written += len as u64;
        progress.inc(len);
    }
}

/// Formats a file size for human readable display.
pub fn file_size_format(bytes: usize) -> String {
    use humansize::FileSize;
    use humansize::file_size_opts::BINARY;
    bytes.file_size(BINARY)
        .map(|x| x.replace(" ", ""))
        .unwrap_or_else(|_| bytes.to_string())
}

/// Checks if we are running in docker
pub fn is_docker() -> bool {
    if fs::metadata("/.dockerenv").is_ok() {
        return true;
    }
    if let Ok(mut f) = fs::File::open("/proc/self/cgroup") {
        let mut s = String::new();
        if f.read_to_string(&mut s).is_ok() && s.find("/docker").is_some() {
            return true;
        }
    }
    false
}

/// Returns a single systemd socket fd if there is one.
pub fn get_systemd_fd() -> Result<Option<RawFd>> {
    let var = match env::var("LISTEN_FDS") {
        Ok(var) => {
            if &var == "0" || &var == "" {
                return Ok(None);
            }
            var
        }
        Err(_) => { return Ok(None); }
    };

    let fds : u32 = var.parse().chain_err(
        || Error::from(ErrorKind::BadEnvVar("LISTEN_FDS", "Not an integer")))?;
    if fds != 1 {
        return Err(ErrorKind::BadEnvVar(
            "LISTEN_FDS", "Exactly one socket needs to be passed").into());
    }

    env::remove_var("LISTEN_FDS");
    Ok(Some(SD_LISTEN_FDS_START))
}

/// A quick binary search by key.
pub fn binsearch_by_key<'a, T, B, F>(slice: &'a [T], item: B, mut f: F) -> Option<&'a T>
    where B: Ord, F: FnMut(&T) -> B
{
    let mut low = 0;
    let mut high = slice.len();

    while low < high {
        let mid = (low + high) / 2;
        let cur_item = &slice[mid as usize];
        if item < f(cur_item) {
            high = mid;
        } else {
            low = mid + 1;
        }
    }

    if low > 0 && low <= slice.len() {
        Some(&slice[low - 1])
    } else {
        None
    }
}

#[test]
fn test_binsearch() {
    let seq = [0u32, 2, 4, 6, 8, 10];
    let m = binsearch_by_key(&seq[..], 5, |&x| x);
    assert_eq!(*m.unwrap(), 4);
}
<commit_msg>Support empty patterns or single string patterns<commit_after>//! Provides various useful utilities.
use std::io;
use std::fs;
use std::fmt;
use std::env;
use std::panic;
use std::os::unix::io::RawFd;
use std::result::Result as StdResult;
use std::io::{Read, Write};
use std::sync::Mutex;

use pbr;
use regex::Regex;
use chrono::Duration;
use serde::{Serialize, Deserialize, de, ser};

use super::{Result, ResultExt, Error, ErrorKind};

pub const SD_LISTEN_FDS_START: RawFd = 3;

/// Helper for serializing/deserializing addresses in string format
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Addr(pub u64);

/// Helper for formatting durations.
pub struct HumanDuration(pub Duration);

impl Into<u64> for Addr {
    fn into(self) -> u64 {
        self.0
    }
}

impl<'a> fmt::Display for HumanDuration {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        macro_rules! try_write {
            ($num:expr, $str:expr) => {
                if $num == 1 { return write!(f, "1 {}", $str); }
                else if $num > 1 { return write!(f, "{} {}s", $num, $str); }
            }
        }

        try_write!(self.0.num_hours(), "hour");
        try_write!(self.0.num_minutes(), "minute");
        try_write!(self.0.num_seconds(), "second");
        write!(f, "0 seconds")
    }
}

impl Serialize for Addr {
    fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
        where S: ser::Serializer
    {
        serializer.serialize_str(&format!("0x{:x}", self.0))
    }
}

impl Deserialize for Addr {
    fn deserialize<D>(deserializer: D) -> StdResult<Addr, D::Error>
        where D: de::Deserializer {
        struct AddrVisitor;

        impl de::Visitor for AddrVisitor {
            type Value = u64;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("an address")
            }

            fn visit_str<E: de::Error>(self, value: &str) -> StdResult<u64, E> {
                if &value[..2] == "0x" {
                    u64::from_str_radix(&value[2..], 16)
                        .map_err(|e| E::custom(e.to_string()))
                } else {
                    u64::from_str_radix(&value, 10)
                        .map_err(|e| E::custom(e.to_string()))
                }
            }

            fn visit_u64<E: de::Error>(self, value: u64) -> StdResult<u64, E> {
                Ok(value)
            }
        }

        deserializer.deserialize_str(AddrVisitor).map(Addr)
    }
}

#[derive(Clone, Debug, Default)]
pub struct RegexFilter {
    patterns: Vec<Regex>,
}

impl Deserialize for RegexFilter {
    fn deserialize<D>(deserializer: D) -> StdResult<RegexFilter, D::Error>
        where D: de::Deserializer {
        struct FilterVisitor;

        fn make_regex<E: de::Error>(value: &str) -> StdResult<Regex, E> {
            Ok(Regex::new(value)
               .map_err(|err| {
                   de::Error::custom(format!(
                       "invalid regular expression '{}': {}", value, err))
               })?)
        }

        impl de::Visitor for FilterVisitor {
            type Value = Vec<Regex>;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a regular expression filter")
            }

            fn visit_seq<V: de::SeqVisitor>(self, mut visitor: V)
                -> StdResult<Vec<Regex>, V::Error>
            {
                let mut rv = vec![];
                while let Some(item) = visitor.visit::<String>()? {
                    rv.push(make_regex(&item)?);
                }
                Ok(rv)
            }

            fn visit_unit<E: de::Error>(self) -> StdResult<Vec<Regex>, E>
            {
                Ok(vec![])
            }

            fn visit_str<E: de::Error>(self, value: &str)
                -> StdResult<Vec<Regex>, E>
            {
                Ok(vec![make_regex(value)?])
            }
        }

        deserializer.deserialize_seq(FilterVisitor).map(|patterns| {
            RegexFilter { patterns: patterns }
        })
    }
}

impl RegexFilter {
    pub fn matches(&self, value: &str) -> bool {
        for pattern in self.patterns.iter() {
            if pattern.is_match(value) {
                return true;
            }
        }
        false
    }
}

/// Helper that runs a function and captures panics.
///
/// The function needs to be reasonably protected against panics.  This
/// might poison mutexes and similar things.
pub fn run_isolated<F>(f: F)
    where F: FnOnce() -> Result<()>, F: Send
{
    let rv = panic::catch_unwind(panic::AssertUnwindSafe(move || {
        if let Err(err) = f() {
            use std::error::Error;
            error!("task failed: {}", &err);
            let mut cause = err.cause();
            while let Some(the_cause) = cause {
                error!("  caused by: {}", the_cause);
                cause = the_cause.cause();
            }
            if let Some(backtrace) = err.backtrace() {
                debug!("  Traceback: {:?}", backtrace);
            }
        }
    }));

    // the default panic handler will already have printed here
    if let Err(_) = rv {
        error!("task panicked!");
    }
}

/// A thread safe progress bar
pub struct ProgressIndicator {
    pb: Mutex<Option<pbr::ProgressBar<io::Stdout>>>,
}

fn make_progress_bar(count: usize) -> pbr::ProgressBar<io::Stdout> {
    let mut pb = pbr::ProgressBar::new(count as u64);
    pb.tick_format("⠇⠋⠙⠸⠴⠦");
    pb.format("[■□□]");
    pb.show_tick = true;
    pb.show_speed = false;
    pb.show_percent = false;
    pb.show_counter = false;
    pb.show_time_left = false;
    pb.message(&format!("{: <44}", ""));
    pb
}

impl ProgressIndicator {
    /// Creates a new progress bar for a given count
    pub fn new(count: usize) -> ProgressIndicator {
        ProgressIndicator {
            pb: Mutex::new(Some(make_progress_bar(count))),
        }
    }

    /// Creates a dummy progress bar that does nothing
    pub fn disabled() -> ProgressIndicator {
        ProgressIndicator {
            pb: Mutex::new(None),
        }
    }

    /// Increments the progress bar by a step counter
    pub fn inc(&self, step: usize) {
        if let Some(ref mut pb) = *self.pb.lock().unwrap() {
            pb.add(step as u64);
        }
    }

    /// Ticks the progress bar without advancing
    pub fn tick(&self) {
        if let Some(ref mut pb) = *self.pb.lock().unwrap() {
            pb.tick();
        }
    }

    /// Sets the current message
    pub fn set_message(&self, msg: &str) {
        if let Some(ref mut pb) = *self.pb.lock().unwrap() {
            pb.message(&format!("  ◦ {: <40}", msg));
            pb.tick();
        }
    }

    /// Marks the progress bar finished and replaces it with a message
    pub fn finish(&self, msg: &str) {
        if let Some(ref mut pb) = *self.pb.lock().unwrap() {
            pb.finish_print(&format!("  ● {}", msg));
            println!("");
        }
    }

    /// Finishes the current bar and adds a new one.  If the progress bar
    /// is disabled this does nothing instead.
    pub fn add_bar(&self, count: usize) {
        let mut pb = self.pb.lock().unwrap();
        if !pb.is_none() {
            *pb = Some(make_progress_bar(count));
        }
    }
}

/// Like ``io::copy`` but advances a progress bar set to bytes.
pub fn copy_with_progress<R: ?Sized, W: ?Sized>(progress: &ProgressIndicator,
                                                reader: &mut R, writer: &mut W)
    -> io::Result<u64>
    where R: Read, W: Write
{
    let mut buf = [0; 16384];
    let mut written = 0;
    loop {
        let len = match reader.read(&mut buf) {
            Ok(0) => return Ok(written),
            Ok(len) => len,
            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };
        writer.write_all(&buf[..len])?;
        written += len as u64;
        progress.inc(len);
    }
}

/// Formats a file size for human readable display.
pub fn file_size_format(bytes: usize) -> String {
    use humansize::FileSize;
    use humansize::file_size_opts::BINARY;
    bytes.file_size(BINARY)
        .map(|x| x.replace(" ", ""))
        .unwrap_or_else(|_| bytes.to_string())
}

/// Checks if we are running in docker
pub fn is_docker() -> bool {
    if fs::metadata("/.dockerenv").is_ok() {
        return true;
    }
    if let Ok(mut f) = fs::File::open("/proc/self/cgroup") {
        let mut s = String::new();
        if f.read_to_string(&mut s).is_ok() && s.find("/docker").is_some() {
            return true;
        }
    }
    false
}

/// Returns a single systemd socket fd if there is one.
pub fn get_systemd_fd() -> Result<Option<RawFd>> {
    let var = match env::var("LISTEN_FDS") {
        Ok(var) => {
            if &var == "0" || &var == "" {
                return Ok(None);
            }
            var
        }
        Err(_) => { return Ok(None); }
    };

    let fds : u32 = var.parse().chain_err(
        || Error::from(ErrorKind::BadEnvVar("LISTEN_FDS", "Not an integer")))?;
    if fds != 1 {
        return Err(ErrorKind::BadEnvVar(
            "LISTEN_FDS", "Exactly one socket needs to be passed").into());
    }

    env::remove_var("LISTEN_FDS");
    Ok(Some(SD_LISTEN_FDS_START))
}

/// A quick binary search by key.
pub fn binsearch_by_key<'a, T, B, F>(slice: &'a [T], item: B, mut f: F) -> Option<&'a T>
    where B: Ord, F: FnMut(&T) -> B
{
    let mut low = 0;
    let mut high = slice.len();

    while low < high {
        let mid = (low + high) / 2;
        let cur_item = &slice[mid as usize];
        if item < f(cur_item) {
            high = mid;
        } else {
            low = mid + 1;
        }
    }

    if low > 0 && low <= slice.len() {
        Some(&slice[low - 1])
    } else {
        None
    }
}

#[test]
fn test_binsearch() {
    let seq = [0u32, 2, 4, 6, 8, 10];
    let m = binsearch_by_key(&seq[..], 5, |&x| x);
    assert_eq!(*m.unwrap(), 4);
}
<|endoftext|>


<commit_before>/// Container for primitive stack allocated `(i32, u32, bool, etc)` as well as heap
/// allocated `(String)` data types. This enum is used by `SyscallParam::parse` method
/// to store the content of the system call parameter's payload.
#[derive(Serialize, Debug)]
#[serde(untagged)]
pub enum Value {
    String(String),
    Int8(i8),
    Int16(i16),
    Int32(i32),
    Int64(i64),
    UInt8(u8),
    UInt16(u16),
    UInt32(u32),
    UInt64(u64),
    None
}
<commit_msg>added more comments<commit_after>/// Container for primitive stack allocated `(i32, u32, bool, etc)` as well as heap
/// allocated `(String)` data types. This enum is used by `SyscallParam::parse` method
/// to store the content of the system call parameter's payload.
/// Some syscall's parameters can have multiple attributes, for example, the socket tuple
/// is comprised of IP address and port number. In that case, the `Value` enum can also have
/// structures associated with it.
#[derive(Serialize, Debug)]
#[serde(untagged)]
pub enum Value {
    String(String),
    Int8(i8),
    Int16(i16),
    Int32(i32),
    Int64(i64),
    UInt8(u8),
    UInt16(u16),
    UInt32(u32),
    UInt64(u64),
    None
}
<|endoftext|>


<commit_before>use rustc_ast as ast;
use rustc_middle::mir::interpret::{
    Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
};
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
use rustc_span::symbol::Symbol;
use rustc_target::abi::Size;

crate fn lit_to_const<'tcx>(
    tcx: TyCtxt<'tcx>,
    lit_input: LitToConstInput<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
    let LitToConstInput { lit, ty, neg } = lit_input;

    let trunc = |n| {
        let param_ty = ParamEnv::reveal_all().and(ty);
        let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
        trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
        let result = width.truncate(n);
        trace!("trunc result: {}", result);
        Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
    };

    let lit = match (lit, &ty.kind()) {
        (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
            let s = s.as_str();
            let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes());
            let allocation = tcx.intern_const_alloc(allocation);
            ConstValue::Slice { data: allocation, start: 0, end: s.len() }
        }
        (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
            if matches!(inner_ty.kind(), ty::Slice(_)) =>
        {
            let allocation = Allocation::from_byte_aligned_bytes(data as &[u8]);
            let allocation = tcx.intern_const_alloc(allocation);
            ConstValue::Slice { data: allocation, start: 0, end: data.len() }
        }
        (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
            let id = tcx.allocate_bytes(data);
            ConstValue::Scalar(Scalar::Ptr(id.into()))
        }
        (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
            ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
        }
        (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
            trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
        }
        (ast::LitKind::Float(n, _), ty::Float(fty)) => {
            parse_float(*n, *fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
        }
        (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
        (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
        (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
        _ => return Err(LitToConstError::TypeError),
    };
    Ok(ty::Const::from_value(tcx, lit, ty))
}

fn parse_float<'tcx>(num: Symbol, fty: ty::FloatTy, neg: bool) -> Result<ConstValue<'tcx>, ()> {
    let num = num.as_str();
    use rustc_apfloat::ieee::{Double, Single};
    let scalar = match fty {
        ty::FloatTy::F32 => {
            num.parse::<f32>().map_err(|_| ())?;
            let mut f = num.parse::<Single>().unwrap_or_else(|e| {
                panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
            });
            if neg {
                f = -f;
            }
            Scalar::from_f32(f)
        }
        ty::FloatTy::F64 => {
            num.parse::<f64>().map_err(|_| ())?;
            let mut f = num.parse::<Double>().unwrap_or_else(|e| {
                panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
            });
            if neg {
                f = -f;
            }
            Scalar::from_f64(f)
        }
    };

    Ok(ConstValue::Scalar(scalar))
}
<commit_msg>Rollup merge of #83018 - oli-obk:float_check, r=davidtwco<commit_after>use rustc_apfloat::Float;
use rustc_ast as ast;
use rustc_middle::mir::interpret::{
    Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
};
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
use rustc_span::symbol::Symbol;
use rustc_target::abi::Size;

crate fn lit_to_const<'tcx>(
    tcx: TyCtxt<'tcx>,
    lit_input: LitToConstInput<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
    let LitToConstInput { lit, ty, neg } = lit_input;

    let trunc = |n| {
        let param_ty = ParamEnv::reveal_all().and(ty);
        let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
        trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
        let result = width.truncate(n);
        trace!("trunc result: {}", result);
        Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
    };

    let lit = match (lit, &ty.kind()) {
        (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
            let s = s.as_str();
            let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes());
            let allocation = tcx.intern_const_alloc(allocation);
            ConstValue::Slice { data: allocation, start: 0, end: s.len() }
        }
        (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
            if matches!(inner_ty.kind(), ty::Slice(_)) =>
        {
            let allocation = Allocation::from_byte_aligned_bytes(data as &[u8]);
            let allocation = tcx.intern_const_alloc(allocation);
            ConstValue::Slice { data: allocation, start: 0, end: data.len() }
        }
        (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
            let id = tcx.allocate_bytes(data);
            ConstValue::Scalar(Scalar::Ptr(id.into()))
        }
        (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
            ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
        }
        (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
            trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
        }
        (ast::LitKind::Float(n, _), ty::Float(fty)) => {
            parse_float(*n, *fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
        }
        (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
        (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
        (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
        _ => return Err(LitToConstError::TypeError),
    };
    Ok(ty::Const::from_value(tcx, lit, ty))
}

fn parse_float<'tcx>(num: Symbol, fty: ty::FloatTy, neg: bool) -> Result<ConstValue<'tcx>, ()> {
    let num = num.as_str();
    use rustc_apfloat::ieee::{Double, Single};
    let scalar = match fty {
        ty::FloatTy::F32 => {
            let rust_f = num.parse::<f32>().map_err(|_| ())?;
            let mut f = num.parse::<Single>().unwrap_or_else(|e| {
                panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
            });
            assert!(
                u128::from(rust_f.to_bits()) == f.to_bits(),
                "apfloat::ieee::Single gave different result for `{}`: \
                 {}({:#x}) vs Rust's {}({:#x})",
                rust_f,
                f,
                f.to_bits(),
                Single::from_bits(rust_f.to_bits().into()),
                rust_f.to_bits()
            );
            if neg {
                f = -f;
            }
            Scalar::from_f32(f)
        }
        ty::FloatTy::F64 => {
            let rust_f = num.parse::<f64>().map_err(|_| ())?;
            let mut f = num.parse::<Double>().unwrap_or_else(|e| {
                panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
            });
            assert!(
                u128::from(rust_f.to_bits()) == f.to_bits(),
                "apfloat::ieee::Double gave different result for `{}`: \
                 {}({:#x}) vs Rust's {}({:#x})",
                rust_f,
                f,
                f.to_bits(),
                Double::from_bits(rust_f.to_bits().into()),
                rust_f.to_bits()
            );
            if neg {
                f = -f;
            }
            Scalar::from_f64(f)
        }
    };

    Ok(ConstValue::Scalar(scalar))
}
<|endoftext|>


<commit_before>use parking_lot::RwLock;
use std::collections::HashMap;

use crate::error::msg::SemError;
use crate::semck;
use crate::ty::BuiltinType;
use crate::vm::{ExtensionId, Fct, FctId, FctKind, FctParent, FctSrc, FileId, NodeMap, VM};

use dora_parser::ast::visit::{self, Visitor};
use dora_parser::ast::{self, Ast};
use dora_parser::lexer::position::Position;

pub fn check<'ast>(vm: &mut VM<'ast>, ast: &'ast Ast, map_extension_defs: &NodeMap<ExtensionId>) {
    let mut clsck = ExtensionCheck {
        vm,
        ast,
        extension_id: None,
        map_extension_defs,
        file_id: 0,
        extension_ty: BuiltinType::Error,
    };

    clsck.check();
}

struct ExtensionCheck<'x, 'ast: 'x> {
    vm: &'x mut VM<'ast>,
    ast: &'ast ast::Ast,
    map_extension_defs: &'x NodeMap<ExtensionId>,
    file_id: u32,

    extension_id: Option<ExtensionId>,
    extension_ty: BuiltinType,
}

impl<'x, 'ast> ExtensionCheck<'x, 'ast> {
    fn check(&mut self) {
        self.visit_ast(self.ast);
    }

    fn visit_extension(&mut self, i: &'ast ast::Impl) {
        assert!(i.trait_type.is_none());
        self.extension_id = Some(*self.map_extension_defs.get(i.id).unwrap());

        self.vm.sym.lock().push_level();

        if let Some(ref type_params) = i.type_params {
            self.check_type_params(self.extension_id.unwrap(), type_params);
        }

        if let Some(class_ty) = semck::read_type(self.vm, self.file_id.into(), &i.class_type) {
            self.extension_ty = class_ty;

            let cls_id = class_ty.cls_id(self.vm).unwrap();
            let cls = self.vm.classes.idx(cls_id);
            let mut cls = cls.write();
            cls.extensions.push(self.extension_id.unwrap());

            let mut extension = self.vm.extensions[self.extension_id.unwrap()].write();
            extension.class_ty = class_ty;
        }

        visit::walk_impl(self, i);

        self.extension_id = None;
        self.vm.sym.lock().pop_level();
    }

    fn check_type_params(
        &mut self,
        _extension_id: ExtensionId,
        _type_params: &'ast [ast::TypeParam],
    ) {
        unimplemented!();
    }
}

impl<'x, 'ast> Visitor<'ast> for ExtensionCheck<'x, 'ast> {
    fn visit_file(&mut self, f: &'ast ast::File) {
        visit::walk_file(self, f);
        self.file_id += 1;
    }

    fn visit_impl(&mut self, i: &'ast ast::Impl) {
        if i.trait_type.is_none() {
            self.visit_extension(i);
        }
    }

    fn visit_method(&mut self, f: &'ast ast::Function) {
        if self.extension_id.is_none() {
            return;
        }

        let extension_id = self.extension_id.unwrap();

        if f.block.is_none() && !f.internal {
            report(
                self.vm,
                self.file_id.into(),
                f.pos,
                SemError::MissingFctBody,
            );
        }

        let kind = if f.internal {
            FctKind::Definition
        } else {
            FctKind::Source(RwLock::new(FctSrc::new()))
        };

        let parent = FctParent::Extension(extension_id);

        let fct = Fct {
            id: FctId(0),
            ast: f,
            pos: f.pos,
            name: f.name,
            param_types: Vec::new(),
            return_type: BuiltinType::Unit,
            parent: parent,
            has_override: f.has_override,
            has_open: f.has_open,
            has_final: f.has_final,
            has_optimize_immediately: f.has_optimize_immediately,
            is_pub: f.is_pub,
            is_static: f.is_static,
            is_abstract: false,
            is_test: f.is_test,
            use_cannon: f.use_cannon,
            internal: f.internal,
            internal_resolved: false,
            overrides: None,
            is_constructor: false,
            vtable_index: None,
            initialized: false,
            impl_for: None,
            file: self.file_id.into(),

            type_params: Vec::new(),
            kind,

            specializations: RwLock::new(HashMap::new()),
        };

        let fct_id = self.vm.add_fct(fct);
        let mut success = true;

        if !self.extension_ty.is_error() {
            let cls_id = self.extension_ty.cls_id(self.vm).unwrap();
            let cls = self.vm.classes.idx(cls_id);
            let cls = cls.read();

            for &method in &cls.methods {
                let method = self.vm.fcts.idx(method);
                let method = method.read();

                if method.name == f.name && method.is_static == f.is_static {
                    let method_name = self.vm.interner.str(method.name).to_string();
                    let msg = SemError::MethodExists(method_name, method.pos);
                    self.vm.diag.lock().report(self.file_id.into(), f.pos, msg);
                    success = false;
                    break;
                }
            }

            if success {
                for &extension_id in &cls.extensions {
                    let extension = self.vm.extensions[extension_id].read();

                    if extension.class_ty.type_params(self.vm)
                        != self.extension_ty.type_params(self.vm)
                    {
                        continue;
                    }

                    let table = if f.is_static {
                        &extension.static_names
                    } else {
                        &extension.instance_names
                    };

                    if let Some(&method_id) = table.get(&f.name) {
                        let method = self.vm.fcts.idx(method_id);
                        let method = method.read();
                        let method_name = self.vm.interner.str(method.name).to_string();
                        let msg = SemError::MethodExists(method_name, method.pos);
                        self.vm.diag.lock().report(self.file_id.into(), f.pos, msg);
                        success = false;
                        break;
                    }
                }
            }
        }

        if success {
            let mut extension = self.vm.extensions[extension_id].write();
            extension.methods.push(fct_id);

            let table = if f.is_static {
                &mut extension.static_names
            } else {
                &mut extension.instance_names
            };

            if !table.contains_key(&f.name) {
                table.insert(f.name, fct_id);
            }
        }
    }
}

fn report(vm: &VM, file: FileId, pos: Position, msg: SemError) {
    vm.diag.lock().report(file, pos, msg);
}

#[cfg(test)]
mod tests {
    use crate::error::msg::SemError;
    use crate::semck::tests::*;

    #[test]
    fn extension_empty() {
        ok("class A impl A {}");
        ok("class A impl A {} impl A {}");
        err(
            "class A impl A[String] {}",
            pos(1, 14),
            SemError::WrongNumberTypeParams(0, 1),
        );

        ok("class A[T] impl A[Int] {} impl A[String] {}");
        err(
            "class A[T: Zero] impl A[Int] {} impl A[String] {}",
            pos(1, 38),
            SemError::TraitBoundNotSatisfied("String".into(), "Zero".into()),
        );
    }

    #[test]
    fn extension_method() {
        ok("class A impl A { fun foo() {} fun bar() {} }");
        err(
            "class A impl A { fun foo() {} fun foo() {} }",
            pos(1, 31),
            SemError::MethodExists("foo".into(), pos(1, 18)),
        );
    }

    #[test]
    fn extension_defined_twice() {
        err(
            "class A { fun foo() {} }
            impl A { fun foo() {} }",
            pos(2, 22),
            SemError::MethodExists("foo".into(), pos(1, 11)),
        );

        err(
            "class A
            impl A { fun foo() {} }
            impl A { fun foo() {} }",
            pos(3, 22),
            SemError::MethodExists("foo".into(), pos(2, 22)),
        );
    }

    #[test]
    fn extension_defined_twice_with_type_params() {
        err(
            "class Foo[T]
            impl Foo[Int] { fun foo() {} }
            impl Foo[Int] { fun foo() {} }",
            pos(3, 29),
            SemError::MethodExists("foo".into(), pos(2, 29)),
        );

        ok("class Foo[T]
            impl Foo[Int] { fun foo() {} }
            impl Foo[Long] { fun foo() {} }");
    }
}
<commit_msg>add test for extension block with illegal type parameter<commit_after>use parking_lot::RwLock;
use std::collections::HashMap;

use crate::error::msg::SemError;
use crate::semck;
use crate::ty::BuiltinType;
use crate::vm::{ExtensionId, Fct, FctId, FctKind, FctParent, FctSrc, FileId, NodeMap, VM};

use dora_parser::ast::visit::{self, Visitor};
use dora_parser::ast::{self, Ast};
use dora_parser::lexer::position::Position;

pub fn check<'ast>(vm: &mut VM<'ast>, ast: &'ast Ast, map_extension_defs: &NodeMap<ExtensionId>) {
    let mut clsck = ExtensionCheck {
        vm,
        ast,
        extension_id: None,
        map_extension_defs,
        file_id: 0,
        extension_ty: BuiltinType::Error,
    };

    clsck.check();
}

struct ExtensionCheck<'x, 'ast: 'x> {
    vm: &'x mut VM<'ast>,
    ast: &'ast ast::Ast,
    map_extension_defs: &'x NodeMap<ExtensionId>,
    file_id: u32,

    extension_id: Option<ExtensionId>,
    extension_ty: BuiltinType,
}

impl<'x, 'ast> ExtensionCheck<'x, 'ast> {
    fn check(&mut self) {
        self.visit_ast(self.ast);
    }

    fn visit_extension(&mut self, i: &'ast ast::Impl) {
        assert!(i.trait_type.is_none());
        self.extension_id = Some(*self.map_extension_defs.get(i.id).unwrap());

        self.vm.sym.lock().push_level();

        if let Some(ref type_params) = i.type_params {
            self.check_type_params(self.extension_id.unwrap(), type_params);
        }

        if let Some(class_ty) = semck::read_type(self.vm, self.file_id.into(), &i.class_type) {
            self.extension_ty = class_ty;

            let cls_id = class_ty.cls_id(self.vm).unwrap();
            let cls = self.vm.classes.idx(cls_id);
            let mut cls = cls.write();
            cls.extensions.push(self.extension_id.unwrap());

            let mut extension = self.vm.extensions[self.extension_id.unwrap()].write();
            extension.class_ty = class_ty;
        }

        visit::walk_impl(self, i);

        self.extension_id = None;
        self.vm.sym.lock().pop_level();
    }

    fn check_type_params(
        &mut self,
        _extension_id: ExtensionId,
        _type_params: &'ast [ast::TypeParam],
    ) {
        unimplemented!();
    }
}

impl<'x, 'ast> Visitor<'ast> for ExtensionCheck<'x, 'ast> {
    fn visit_file(&mut self, f: &'ast ast::File) {
        visit::walk_file(self, f);
        self.file_id += 1;
    }

    fn visit_impl(&mut self, i: &'ast ast::Impl) {
        if i.trait_type.is_none() {
            self.visit_extension(i);
        }
    }

    fn visit_method(&mut self, f: &'ast ast::Function) {
        if self.extension_id.is_none() {
            return;
        }

        let extension_id = self.extension_id.unwrap();

        if f.block.is_none() && !f.internal {
            report(
                self.vm,
                self.file_id.into(),
                f.pos,
                SemError::MissingFctBody,
            );
        }

        let kind = if f.internal {
            FctKind::Definition
        } else {
            FctKind::Source(RwLock::new(FctSrc::new()))
        };

        let parent = FctParent::Extension(extension_id);

        let fct = Fct {
            id: FctId(0),
            ast: f,
            pos: f.pos,
            name: f.name,
            param_types: Vec::new(),
            return_type: BuiltinType::Unit,
            parent: parent,
            has_override: f.has_override,
            has_open: f.has_open,
            has_final: f.has_final,
            has_optimize_immediately: f.has_optimize_immediately,
            is_pub: f.is_pub,
            is_static: f.is_static,
            is_abstract: false,
            is_test: f.is_test,
            use_cannon: f.use_cannon,
            internal: f.internal,
            internal_resolved: false,
            overrides: None,
            is_constructor: false,
            vtable_index: None,
            initialized: false,
            impl_for: None,
            file: self.file_id.into(),

            type_params: Vec::new(),
            kind,

            specializations: RwLock::new(HashMap::new()),
        };

        let fct_id = self.vm.add_fct(fct);
        let mut success = true;

        if !self.extension_ty.is_error() {
            let cls_id = self.extension_ty.cls_id(self.vm).unwrap();
            let cls = self.vm.classes.idx(cls_id);
            let cls = cls.read();

            for &method in &cls.methods {
                let method = self.vm.fcts.idx(method);
                let method = method.read();

                if method.name == f.name && method.is_static == f.is_static {
                    let method_name = self.vm.interner.str(method.name).to_string();
                    let msg = SemError::MethodExists(method_name, method.pos);
                    self.vm.diag.lock().report(self.file_id.into(), f.pos, msg);
                    success = false;
                    break;
                }
            }

            if success {
                for &extension_id in &cls.extensions {
                    let extension = self.vm.extensions[extension_id].read();

                    if extension.class_ty.type_params(self.vm)
                        != self.extension_ty.type_params(self.vm)
                    {
                        continue;
                    }

                    let table = if f.is_static {
                        &extension.static_names
                    } else {
                        &extension.instance_names
                    };

                    if let Some(&method_id) = table.get(&f.name) {
                        let method = self.vm.fcts.idx(method_id);
                        let method = method.read();
                        let method_name = self.vm.interner.str(method.name).to_string();
                        let msg = SemError::MethodExists(method_name, method.pos);
                        self.vm.diag.lock().report(self.file_id.into(), f.pos, msg);
                        success = false;
                        break;
                    }
                }
            }
        }

        if success {
            let mut extension = self.vm.extensions[extension_id].write();
            extension.methods.push(fct_id);

            let table = if f.is_static {
                &mut extension.static_names
            } else {
                &mut extension.instance_names
            };

            if !table.contains_key(&f.name) {
                table.insert(f.name, fct_id);
            }
        }
    }
}

fn report(vm: &VM, file: FileId, pos: Position, msg: SemError) {
    vm.diag.lock().report(file, pos, msg);
}

#[cfg(test)]
mod tests {
    use crate::error::msg::SemError;
    use crate::semck::tests::*;

    #[test]
    fn extension_empty() {
        ok("class A impl A {}");
        ok("class A impl A {} impl A {}");
        err(
            "class A impl A[String] {}",
            pos(1, 14),
            SemError::WrongNumberTypeParams(0, 1),
        );

        ok("class A[T] impl A[Int] {} impl A[String] {}");
        err(
            "class A[T: Zero] impl A[Int] {} impl A[String] {}",
            pos(1, 38),
            SemError::TraitBoundNotSatisfied("String".into(), "Zero".into()),
        );
    }

    #[test]
    fn extension_method() {
        ok("class A impl A { fun foo() {} fun bar() {} }");
        err(
            "class A impl A { fun foo() {} fun foo() {} }",
            pos(1, 31),
            SemError::MethodExists("foo".into(), pos(1, 18)),
        );
    }

    #[test]
    fn extension_defined_twice() {
        err(
            "class A { fun foo() {} }
            impl A { fun foo() {} }",
            pos(2, 22),
            SemError::MethodExists("foo".into(), pos(1, 11)),
        );

        err(
            "class A
            impl A { fun foo() {} }
            impl A { fun foo() {} }",
            pos(3, 22),
            SemError::MethodExists("foo".into(), pos(2, 22)),
        );
    }

    #[test]
    fn extension_defined_twice_with_type_params_in_class() {
        err(
            "class Foo[T]
            impl Foo[Int] { fun foo() {} }
            impl Foo[Int] { fun foo() {} }",
            pos(3, 29),
            SemError::MethodExists("foo".into(), pos(2, 29)),
        );

        ok("class Foo[T]
            impl Foo[Int] { fun foo() {} }
            impl Foo[Long] { fun foo() {} }");
    }

    #[test]
    fn extension_with_illegal_type_param_in_class() {
        err(
            "trait MyTrait {}
            class Foo[T: MyTrait]
            impl Foo[String] {}
        ",
            pos(3, 18),
            SemError::TraitBoundNotSatisfied("String".into(), "MyTrait".into()),
        );
    }
}
<|endoftext|>


<commit_before>/// Populated while receiving events from the markdown parser
#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct Header {
    #[serde(skip_serializing)]
    pub level: i32,
    pub id: String,
    pub permalink: String,
    pub title: String,
    pub children: Vec<Header>,
}

impl Header {
    pub fn new(level: i32) -> Header {
        Header {
            level,
            id: String::new(),
            permalink: String::new(),
            title: String::new(),
            children: Vec::new(),
        }
    }
}

impl Default for Header {
    fn default() -> Self {
        Header::new(0)
    }
}

/// Converts the flat temp headers into a nested set of headers
/// representing the hierarchy
pub fn make_table_of_contents(headers: Vec<Header>) -> Vec<Header> {
    let mut toc = vec![];
    'parent: for header in headers {
        if toc.is_empty() {
            toc.push(header);
            continue;
        }

        // See if we have to insert as a child of a previous header
        for h in toc.iter_mut().rev() {
            // Look in its children first
            for child in h.children.iter_mut().rev() {
                if header.level > child.level {
                    child.children.push(header);
                    continue 'parent;
                }
            }
            if header.level > h.level {
                h.children.push(header);
                continue 'parent;
            }
        }

        // Nop, just insert it
        toc.push(header)
    }

    toc
}

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

    #[test]
    fn can_make_basic_toc() {
        let input = vec![Header::new(1), Header::new(1), Header::new(1)];
        let toc = make_table_of_contents(input);
        assert_eq!(toc.len(), 3);
    }

    #[test]
    fn can_make_more_complex_toc() {
        let input = vec![
            Header::new(1),
            Header::new(2),
            Header::new(2),
            Header::new(3),
            Header::new(2),
            Header::new(1),
            Header::new(2),
            Header::new(3),
            Header::new(3),
        ];
        let toc = make_table_of_contents(input);
        assert_eq!(toc.len(), 2);
        assert_eq!(toc[0].children.len(), 3);
        assert_eq!(toc[1].children.len(), 1);
        assert_eq!(toc[0].children[1].children.len(), 1);
        assert_eq!(toc[1].children[0].children.len(), 2);
    }

    #[test]
    fn can_make_messy_toc() {
        let input = vec![
            Header::new(3),
            Header::new(2),
            Header::new(2),
            Header::new(3),
            Header::new(2),
            Header::new(1),
            Header::new(4),
        ];
        let toc = make_table_of_contents(input);
        println!("{:#?}", toc);
        assert_eq!(toc.len(), 5);
        assert_eq!(toc[2].children.len(), 1);
        assert_eq!(toc[4].children.len(), 1);
    }
}
<commit_msg>Fix ToC generation for heading levels > 3 (bugfix) (#774)<commit_after>/// Populated while receiving events from the markdown parser
#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct Header {
    #[serde(skip_serializing)]
    pub level: i32,
    pub id: String,
    pub permalink: String,
    pub title: String,
    pub children: Vec<Header>,
}

impl Header {
    pub fn new(level: i32) -> Header {
        Header {
            level,
            id: String::new(),
            permalink: String::new(),
            title: String::new(),
            children: Vec::new(),
        }
    }
}

impl Default for Header {
    fn default() -> Self {
        Header::new(0)
    }
}

// Takes a potential (mutable) parent and a header to try and insert into
// Returns true when it performed the insertion, false otherwise
fn insert_into_parent(potential_parent: Option<&mut Header>, header: &Header) -> bool {
    match potential_parent {
        None => {
            // No potential parent to insert into so it needs to be insert higher
            return false;
        },
        Some(parent) => {
            let diff = header.level - parent.level;
            if diff <= 0 {
                // Heading is same level or higher so we don't insert here
                return false;
            }
            if diff == 1 {
                // We have a direct child of the parent
                parent.children.push(header.clone());
                return true;
            }
            // We need to go deeper
            if !insert_into_parent(parent.children.iter_mut().last(), header) {
                // No, we need to insert it here
                parent.children.push(header.clone());
            }
            return true;
        }
    }
}

/// Converts the flat temp headers into a nested set of headers
/// representing the hierarchy
pub fn make_table_of_contents(headers: Vec<Header>) -> Vec<Header> {
    let mut toc = vec![];
    for header in headers {
        if toc.is_empty() {
            // First header, nothing to compare it with
            toc.push(header);
            continue;
        }

        // We try to insert the current header in a previous one
        match insert_into_parent(toc.iter_mut().last(), &header) {
            true => {
                // Header was successfully inserted as a child of a previous element
                continue;
            },
            false => {
                // Couldn't insert in a previous header, so it's a top-level header
                toc.push(header);
                continue;
            }
        }
    }

    toc
}

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

    #[test]
    fn can_make_basic_toc() {
        let input = vec![Header::new(1), Header::new(1), Header::new(1)];
        let toc = make_table_of_contents(input);
        assert_eq!(toc.len(), 3);
    }

    #[test]
    fn can_make_more_complex_toc() {
        let input = vec![
            Header::new(1),
            Header::new(2),
            Header::new(2),
            Header::new(3),
            Header::new(2),
            Header::new(1),
            Header::new(2),
            Header::new(3),
            Header::new(3),
        ];
        let toc = make_table_of_contents(input);
        assert_eq!(toc.len(), 2);
        assert_eq!(toc[0].children.len(), 3);
        assert_eq!(toc[1].children.len(), 1);
        assert_eq!(toc[0].children[1].children.len(), 1);
        assert_eq!(toc[1].children[0].children.len(), 2);
    }

    #[test]
    fn can_make_deep_toc() {
        let input = vec![
            Header::new(1),
            Header::new(2),
            Header::new(3),
            Header::new(4),
            Header::new(5),
            Header::new(4),
        ];
        let toc = make_table_of_contents(input);
        assert_eq!(toc.len(), 1);
        assert_eq!(toc[0].children.len(), 1);
        assert_eq!(toc[0].children[0].children.len(), 1);
        assert_eq!(toc[0].children[0].children[0].children.len(), 2);
        assert_eq!(toc[0].children[0].children[0].children[0].children.len(), 1);
    }

    #[test]
    fn can_make_deep_messy_toc() {
        let input = vec![
            Header::new(2), // toc[0]
            Header::new(3),
            Header::new(4),
            Header::new(5),
            Header::new(4),
            Header::new(2), // toc[1]
            Header::new(1), // toc[2]
            Header::new(2),
            Header::new(3),
            Header::new(4),
        ];
        let toc = make_table_of_contents(input);
        assert_eq!(toc.len(), 3);
        assert_eq!(toc[0].children.len(), 1);
        assert_eq!(toc[0].children[0].children.len(), 2);
        assert_eq!(toc[0].children[0].children[0].children.len(), 1);
        assert_eq!(toc[1].children.len(), 0);
        assert_eq!(toc[2].children.len(), 1);
        assert_eq!(toc[2].children[0].children.len(), 1);
        assert_eq!(toc[2].children[0].children[0].children.len(), 1);
    }

    #[test]
    fn can_make_messy_toc() {
        let input = vec![
            Header::new(3),
            Header::new(2),
            Header::new(2),
            Header::new(3),
            Header::new(2),
            Header::new(1),
            Header::new(4),
        ];
        let toc = make_table_of_contents(input);
        println!("{:#?}", toc);
        assert_eq!(toc.len(), 5);
        assert_eq!(toc[2].children.len(), 1);
        assert_eq!(toc[4].children.len(), 1);
    }
}
<|endoftext|>


<commit_before>extern crate metl;

use metl::Device;
use metl::extras::window::{WindowBuilder};

fn main() {
    let window = WindowBuilder::new().build().unwrap();
    let device = Device::system_default_device().unwrap();

    // todo(burtonageo): implement
}
<commit_msg>Small style nit<commit_after>extern crate metl;

use metl::extras::window::{WindowBuilder};

fn main() {
    let window = WindowBuilder::new().build().unwrap();
    let device = metl::Device::system_default_device().unwrap();

    // todo(burtonageo): implement
}
<|endoftext|>


<commit_before>use {success,expect,Matcher,MatchResult};
use std::fmt;
use std::io::fs::PathExtensions;

#[derive(Copy)]
pub enum PathType {
  AnyType,
  File,
  Dir
}

#[derive(Copy)]
pub struct ExistingPath {
  path_type: PathType
}

impl ExistingPath {
  fn match_path_type(&self, actual: &Path) -> MatchResult {
    match self.path_type {
      PathType::File => expect(actual.is_file(), format!("`{}` was not a file", actual.display())),
      PathType::Dir => expect(actual.is_dir(), format!("`{}` was not a dir", actual.display())),
      _ => success(),
    }
  }
}

impl fmt::Display for ExistingPath {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "an existing file")
    }
}

impl<'a> Matcher<&'a Path> for ExistingPath {
  fn matches(&self, actual: &Path) -> MatchResult {
    expect(actual.exists(), format!("{} was missing", actual.display()))
      .and(self.match_path_type(actual))
  }
}

pub fn existing_path() -> ExistingPath {
  ExistingPath { path_type: PathType::AnyType }
}

pub fn existing_file() -> ExistingPath {
  ExistingPath { path_type: PathType::File }
}

pub fn existing_dir() -> ExistingPath {
  ExistingPath { path_type: PathType::Dir }
}

#[cfg(test)]
mod test {
  use std::os;
  use {assert_that,is,is_not,existing_file,existing_dir,existing_path};

  #[test]
  fn test_with_existing_file() {
    let path = path(os::getenv("TEST_EXISTS_FILE"), "./README.md");

    assert_that(&path, is(existing_path()));
    assert_that(&path, is(existing_file()));
    assert_that(&path, is_not(existing_dir()));
  }

  #[test]
  fn test_with_existing_dir() {
    let path = path(os::getenv("TEST_EXISTS_DIR"), "./target");

    assert_that(&path, is(existing_path()));
    assert_that(&path, is(existing_dir()));
    assert_that(&path, is_not(existing_file()));
  }

  #[test]
  fn test_with_nonexisting_path() {
    let path = path(os::getenv("TEST_EXISTS_NONE"), "./zomg.txt");

    assert_that(&path, is_not(existing_path()));
    assert_that(&path, is_not(existing_file()));
    assert_that(&path, is_not(existing_dir()));
  }

  fn path(path: Option<String>, default: &str) -> Path {
    Path::new(path.unwrap_or(default.to_string()))
  }
}
<commit_msg>Switch to old_io<commit_after>use {success,expect,Matcher,MatchResult};
use std::fmt;
use std::old_io::fs::PathExtensions;

#[derive(Copy)]
pub enum PathType {
  AnyType,
  File,
  Dir
}

#[derive(Copy)]
pub struct ExistingPath {
  path_type: PathType
}

impl ExistingPath {
  fn match_path_type(&self, actual: &Path) -> MatchResult {
    match self.path_type {
      PathType::File => expect(actual.is_file(), format!("`{}` was not a file", actual.display())),
      PathType::Dir => expect(actual.is_dir(), format!("`{}` was not a dir", actual.display())),
      _ => success(),
    }
  }
}

impl fmt::Display for ExistingPath {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "an existing file")
    }
}

impl<'a> Matcher<&'a Path> for ExistingPath {
  fn matches(&self, actual: &Path) -> MatchResult {
    expect(actual.exists(), format!("{} was missing", actual.display()))
      .and(self.match_path_type(actual))
  }
}

pub fn existing_path() -> ExistingPath {
  ExistingPath { path_type: PathType::AnyType }
}

pub fn existing_file() -> ExistingPath {
  ExistingPath { path_type: PathType::File }
}

pub fn existing_dir() -> ExistingPath {
  ExistingPath { path_type: PathType::Dir }
}

#[cfg(test)]
mod test {
  use std::os;
  use {assert_that,is,is_not,existing_file,existing_dir,existing_path};

  #[test]
  fn test_with_existing_file() {
    let path = path(os::getenv("TEST_EXISTS_FILE"), "./README.md");

    assert_that(&path, is(existing_path()));
    assert_that(&path, is(existing_file()));
    assert_that(&path, is_not(existing_dir()));
  }

  #[test]
  fn test_with_existing_dir() {
    let path = path(os::getenv("TEST_EXISTS_DIR"), "./target");

    assert_that(&path, is(existing_path()));
    assert_that(&path, is(existing_dir()));
    assert_that(&path, is_not(existing_file()));
  }

  #[test]
  fn test_with_nonexisting_path() {
    let path = path(os::getenv("TEST_EXISTS_NONE"), "./zomg.txt");

    assert_that(&path, is_not(existing_path()));
    assert_that(&path, is_not(existing_file()));
    assert_that(&path, is_not(existing_dir()));
  }

  fn path(path: Option<String>, default: &str) -> Path {
    Path::new(path.unwrap_or(default.to_string()))
  }
}
<|endoftext|>


<commit_before>use image;
use num;

pub type T = image::Rgba<u8>;

pub fn empty() -> T {
  image::Rgba { data: [0; 4] }
}

#[test]
fn assert_mem_layout() {
  assert!(std::mem::size_of::<T>() == std::mem::size_of::<u8>());
}

pub fn diff(t1: T, t2: T) -> u32 {
  assert!(t1.data[3] == t2.data[3]);
  let r =
    num::abs(t1.data[0] as i32 - t2.data[0] as i32) +
    num::abs(t1.data[1] as i32 - t2.data[1] as i32) +
    num::abs(t1.data[2] as i32 - t2.data[2] as i32);
  r as u32
}
<commit_msg>remove old tests<commit_after>use image;
use num;

pub type T = image::Rgba<u8>;

pub fn empty() -> T {
  image::Rgba { data: [0; 4] }
}

pub fn diff(t1: T, t2: T) -> u32 {
  assert!(t1.data[3] == t2.data[3]);
  let r =
    num::abs(t1.data[0] as i32 - t2.data[0] as i32) +
    num::abs(t1.data[1] as i32 - t2.data[1] as i32) +
    num::abs(t1.data[2] as i32 - t2.data[2] as i32);
  r as u32
}
<|endoftext|>


<commit_before>//! Printing-related traits and implementations.

use std::fmt ;
use std::io ;

use ::{ Zdd, ZddTreeOps } ;
use ::ZddTree::* ;

/// Printing-related stuff for ZDDs.
pub trait ZddPrint<Label> {
  /// Pretty prints a ZDD with a prefix.
  fn print(& self, String) ;
  /// Print a ZDD as a graphviz graph to a file.
  fn graph_to_file(& self, & str) -> io::Result<()> ;
}

/// Prints a ZDD as a graphviz graph to a `Write`.
fn graph_print<Label: fmt::Display + Ord + Copy>(
  zdd: & Zdd<Label>, fmt: & mut io::Write, root: & 'static str
) -> io::Result<()> {
  use std::collections::HashSet ;
  let mut mem = HashSet::new() ;

  let mut to_do = vec![ (root.to_string(), "", false, zdd.clone()) ] ;
  let has_one_style= " arrowtail=odot  dir=both" ;

  loop {
    if let Some((parent, edge_lbl, has_one, zdd)) = to_do.pop() {
      let style = if has_one { has_one_style } else { "" } ;
      match zdd.get() {
        & Zero => try!(
          write!(
            fmt, "  {} -> 0 [{}{}] ;\n", parent, edge_lbl, style
          )
        ),
        & HasOne(ref kid) => to_do.push(
          (parent, edge_lbl, true, kid.clone())
        ),
        & Node(ref lbl, ref left, ref right) => {
          try!(
            write!(
              fmt, "  {} -> {} [{}{}] ;\n",
              parent, lbl, edge_lbl, style
            )
          ) ;
          if ! mem.contains(& zdd) {
            mem.insert(zdd.clone()) ;
            to_do.push(
              (format!("{}", lbl), "arrowhead=empty", false, right.clone())
            ) ;
            to_do.push(
              (format!("{}", lbl), "", false, left.clone())
            )
          }
        },
      }
    } else {
      return Ok(())
    }
  }
}

impl<Label: fmt::Display + Ord + Copy> ZddPrint<Label> for Zdd<Label> {

  fn print(& self, pref: String) {
    println!("{}{{", pref) ;
    for set in self.to_set().into_iter() {
      print!("{}  {{ ", pref) ;
      let mut first = true ;
      for e in set.into_iter() {
        print!(
          "{}{}", if first { first = false ; "" } else { ", " }, e
        )
      } ;
      println!(" }}") ;
    } ;
    println!("{}}}", pref)
  }

  fn graph_to_file(& self, file: & str) -> io::Result<()> {
    use std::fs::{ OpenOptions } ;
    use std::io::Write ;
    use std::process::Command ;
    let root = "root" ;
    match OpenOptions::new().write(true).create(true).open(
      format!("{}.gv", file)
    ) {
      Ok(mut f) => {
        let fmt = & mut f ;
        try!( write!(fmt, "digraph {{\n\n") ) ;
        try!( write!(fmt, "  graph [bgcolor=black margin=0.0] ;\n") ) ;
        try!( write!(fmt, "  node [style=invisible] ; {} ;\n\n", root) ) ;
        try!( write!(fmt,
          "  node [\
              style=filled \
              fillcolor=black \
              fontcolor=\"#1e90ff\" \
              color=\"#666666\"\
          ] ;\n"
        ) ) ;
        try!( write!(fmt,
          "  edge [color=\"#1e90ff\" fontcolor=\"#222222\"] ;\n\n"
        ) ) ;
        try!( write!(fmt,
          "  node [shape=doublecircle] ; 0 ;\n"
        ) ) ;
        try!( write!(fmt, "  node [shape=circle] ;\n") ) ;
        try!( graph_print(self, fmt, root) ) ;
        try!( write!(fmt, "}}\n") ) ;
        try!( fmt.flush() ) ;
      },
      Err(e) => panic!("{}", e),
    }
    let _ = Command::new("dot").arg("-Tpdf").arg("-o").arg(
      format!("{}.pdf", file)
    ).arg(
      format!("{}.gv", file)
    ).output().unwrap() ;
    Ok(())
  }
}<commit_msg>Bug fix in graphviz printing.<commit_after>//! Printing-related traits and implementations.

use std::fmt ;
use std::io ;

use ::{ Zdd, ZddTreeOps } ;
use ::ZddTree::* ;

/// Printing-related stuff for ZDDs.
pub trait ZddPrint<Label> {
  /// Pretty prints a ZDD with a prefix.
  fn print(& self, String) ;
  /// Print a ZDD as a graphviz graph to a file.
  fn graph_to_file(& self, & str) -> io::Result<()> ;
}

/// Prints a ZDD as a graphviz graph to a `Write`.
fn graph_print<Label: fmt::Display + Ord + Copy>(
  fmt: & mut io::Write,
  zdd: & Zdd<Label>,
  root: & 'static str,
  zero: & 'static str
) -> io::Result<()> {
  use std::collections::HashSet ;
  let mut mem = HashSet::new() ;

  let mut to_do = vec![ (root.to_string(), "", false, zdd.clone()) ] ;
  let has_one_style= " arrowtail=odot  dir=both" ;

  loop {
    if let Some((parent, edge_lbl, has_one, zdd)) = to_do.pop() {
      let style = if has_one { has_one_style } else { "" } ;
      match zdd.get() {
        & Zero => try!(
          write!(
            fmt, "  {} -> {} [{}{}] ;\n", parent, zero, edge_lbl, style
          )
        ),
        & HasOne(ref kid) => to_do.push(
          (parent, edge_lbl, true, kid.clone())
        ),
        & Node(ref lbl, ref left, ref right) => {
          let name = zdd.hkey().to_string() ;
          try!(write!(fmt, "  {} [label=\"{}\"] ; \n", name, lbl)) ;
          try!(
            write!(
              fmt, "  {} -> {} [{}{}] ;\n",
              parent, name, edge_lbl, style
            )
          ) ;
          if ! mem.contains(& zdd) {
            mem.insert(zdd.clone()) ;
            to_do.push(
              (name.clone(), "arrowhead=empty", false, right.clone())
            ) ;
            to_do.push(
              (name, "", false, left.clone())
            )
          }
        },
      }
    } else {
      return Ok(())
    }
  }
}

impl<Label: fmt::Display + Ord + Copy> ZddPrint<Label> for Zdd<Label> {

  fn print(& self, pref: String) {
    println!("{}{{", pref) ;
    for set in self.to_set().into_iter() {
      print!("{}  {{ ", pref) ;
      let mut first = true ;
      for e in set.into_iter() {
        print!(
          "{}{}", if first { first = false ; "" } else { ", " }, e
        )
      } ;
      println!(" }}") ;
    } ;
    println!("{}}}", pref)
  }

  fn graph_to_file(& self, file: & str) -> io::Result<()> {
    use std::fs::{ OpenOptions } ;
    use std::io::Write ;
    use std::process::Command ;
    let root = "root_of_the_zdd" ;
    let zero = "zero_of_the_zdd" ;
    match OpenOptions::new().write(true).create(true).truncate(true).open(
      format!("{}.gv", file)
    ) {
      Ok(mut f) => {
        let fmt = & mut f ;
        try!( write!(fmt, "digraph {{\n\n") ) ;
        try!( write!(fmt, "  graph [bgcolor=black margin=0.0] ;\n") ) ;
        try!( write!(fmt, "  node [style=invisible] ; {} ;\n\n", root) ) ;
        try!( write!(fmt,
          "  node [\
              style=filled \
              fillcolor=black \
              fontcolor=\"#1e90ff\" \
              color=\"#666666\"\
          ] ;\n"
        ) ) ;
        try!( write!(fmt,
          "  edge [color=\"#1e90ff\" fontcolor=\"#222222\"] ;\n\n"
        ) ) ;
        try!( write!(fmt,
          "  node [shape=doublecircle] ; {} [label=\"{{}}\"] ;\n", zero
        ) ) ;
        try!( write!(fmt, "  node [shape=circle] ;\n") ) ;
        try!( graph_print(fmt, self, root, zero) ) ;
        try!( write!(fmt, "}}\n") ) ;
        try!( fmt.flush() ) ;
      },
      Err(e) => panic!("{}", e),
    }
    let _ = Command::new("dot").arg("-Tpdf").arg("-o").arg(
      format!("{}.pdf", file)
    ).arg(
      format!("{}.gv", file)
    ).output().unwrap() ;
    Ok(())
  }
}<|endoftext|>


<commit_before>use std::fmt;
use std::borrow::Cow;

use attr::AttributeList;
use escape::Escaped;

#[derive(Clone, Debug)]
pub enum Token<'a> {
    StartTag {
        name: Cow<'a, str>,
        attrs: AttributeList<'a>,
        /// Marker indicating self-closing tags such as `<br />`
        self_closing: bool,
    },
    EndTag {
        name: Cow<'a, str>,
    },
    /// The text contained will be escaped on `Display`.
    Text(Cow<'a, str>),
    /// The text contained will be `Display`ed as-is.
    RawText(Cow<'a, str>),
    /// For text contained within `<!--` and `-->`
    Comment(Cow<'a, str>),
}

impl<'a> Token<'a> {
    pub fn start_tag<S>(name: S, attrs: AttributeList<'a>) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::StartTag {
            name: name.into(),
            attrs: attrs,
            self_closing: false,
        }
    }

    pub fn end_tag<S>(name: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::EndTag { name: name.into() }
    }

    pub fn text<S>(s: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::Text(s.into())
    }

    pub fn raw_text<S>(s: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::RawText(s.into())
    }

    pub fn comment<S>(s: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::Comment(s.into())
    }

    /// If `self` is a `StartTag`, returns the `Token` after setting
    /// `self_closing` to `true`; otherwise, it is a no-op.
    pub fn closed(self) -> Token<'a> {
        if let Token::StartTag { name, attrs, .. } = self {
            Token::StartTag {
                name: name,
                attrs: attrs,
                self_closing: true,
            }
        } else {
            self
        }
    }
}

impl<'a> fmt::Display for Token<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Token::StartTag { ref name, ref attrs, self_closing } => {
                try!(write!(f, "<{}", name));
                for attr in attrs.iter() {
                    try!(write!(f, " {}", attr));
                }
                if self_closing {
                    write!(f, " />")
                } else {
                    write!(f, ">")
                }
            }
            Token::EndTag { ref name } => write!(f, "</{}>", name),
            Token::Text(ref text) => write!(f, "{}", Escaped(text)),
            Token::RawText(ref text) => write!(f, "{}", text),
            Token::Comment(ref text) => write!(f, "<!--{}-->", text),
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn token_variants() {
        use Token;
        use attr::AttributeList;

        let start_tag = Token::start_tag("tag", AttributeList::empty());
        assert_eq!(format!("{}", start_tag), "<tag>");

        let end_tag = Token::end_tag("tag");
        assert_eq!(format!("{}", end_tag), "</tag>");

        let text = Token::text("<bomb>");
        assert_eq!(format!("{}", text), "<bomb>");

        let raw_text = Token::raw_text("<bomb>");
        assert_eq!(format!("{}", raw_text), "<bomb>");

        let comment = Token::comment("Multi\nline\ncomment");
        assert_eq!(format!("{}", comment), "<!--Multi\nline\ncomment-->");
    }
}
<commit_msg>Add Token::DOCTYPE variant + more docs<commit_after>use std::fmt;
use std::borrow::Cow;

use attr::AttributeList;
use escape::Escaped;

#[derive(Clone, Debug)]
/// An HTML token. By convention, `Token::Text` should be preferred over
/// `Token::RawText` when a piece of text can be represented by both. For
/// instance, use `Token::Text` when tokenizing whitespaces or line-breaks, but
/// use `Token::RawText` for representing all text inside `<style>` tag.
///
/// When `Display`ing a `Token`, the output stream is assumed to be Unicode, and
/// therefore only five characters are escaped: `&`, `<`, `>`, `"`, and `'`
/// ([ref](http://stackoverflow.com/a/7382028)).
pub enum Token<'a> {
    StartTag {
        name: Cow<'a, str>,
        attrs: AttributeList<'a>,
        /// Marker indicating self-closing tags such as `<br />`
        self_closing: bool,
    },
    EndTag {
        name: Cow<'a, str>,
    },
    /// The text contained will be escaped on `Display`.
    Text(Cow<'a, str>),
    /// The text contained will be `Display`ed as-is.
    RawText(Cow<'a, str>),
    /// Comments contained within `<!--` and `-->`. No validation is done to
    /// ensure that the text does not contain `-->`.
    Comment(Cow<'a, str>),
    /// The HTML5 DOCTYPE declaration
    DOCTYPE,
}

impl<'a> Token<'a> {
    pub fn start_tag<S>(name: S, attrs: AttributeList<'a>) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::StartTag {
            name: name.into(),
            attrs: attrs,
            self_closing: false,
        }
    }

    pub fn end_tag<S>(name: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::EndTag { name: name.into() }
    }

    pub fn text<S>(s: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::Text(s.into())
    }

    pub fn raw_text<S>(s: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::RawText(s.into())
    }

    pub fn comment<S>(s: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::Comment(s.into())
    }

    /// If `self` is a `StartTag`, returns the `Token` after setting
    /// `self_closing` to `true`; otherwise, it is a no-op.
    pub fn closed(self) -> Token<'a> {
        if let Token::StartTag { name, attrs, .. } = self {
            Token::StartTag {
                name: name,
                attrs: attrs,
                self_closing: true,
            }
        } else {
            self
        }
    }
}

impl<'a> fmt::Display for Token<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Token::StartTag { ref name, ref attrs, self_closing } => {
                try!(write!(f, "<{}", name));
                for attr in attrs.iter() {
                    try!(write!(f, " {}", attr));
                }
                if self_closing {
                    write!(f, " />")
                } else {
                    write!(f, ">")
                }
            }
            Token::EndTag { ref name } => write!(f, "</{}>", name),
            Token::Text(ref text) => write!(f, "{}", Escaped(text)),
            Token::RawText(ref text) => write!(f, "{}", text),
            Token::Comment(ref text) => write!(f, "<!--{}-->", text),
            Token::DOCTYPE => write!(f, "<!DOCTYPE html>"),
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn token_variants() {
        use Token;
        use attr::AttributeList;

        let start_tag = Token::start_tag("tag", AttributeList::empty());
        assert_eq!(format!("{}", start_tag), "<tag>");

        let end_tag = Token::end_tag("tag");
        assert_eq!(format!("{}", end_tag), "</tag>");

        let text = Token::text("<bomb>");
        assert_eq!(format!("{}", text), "<bomb>");

        let raw_text = Token::raw_text("<bomb>");
        assert_eq!(format!("{}", raw_text), "<bomb>");

        let comment = Token::comment("Multi\nline\ncomment");
        assert_eq!(format!("{}", comment), "<!--Multi\nline\ncomment-->");

        assert_eq!(format!("{}", Token::DOCTYPE), "<!DOCTYPE html>");
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::string::ToString;
use std::default::Default;
use rustc_serialize::json::{Json,ToJson};

use parse::*;

// subtypes shared across record types

make_prop_type!(File, "File",
    url:  String => "url",
    typ:  Option<String> => "type",
    name: Option<String> => "name",
    size: Option<String> => "size"
);

<commit_msg>Fix File.size, its a number, not a string<commit_after>use std::collections::BTreeMap;
use std::string::ToString;
use std::default::Default;
use rustc_serialize::json::{Json,ToJson};

use parse::*;

// subtypes shared across record types

make_prop_type!(File, "File",
    url:  String => "url",
    typ:  Option<String> => "type",
    name: Option<String> => "name",
    size: Option<u64> => "size"
);

<|endoftext|>


<commit_before>//! Types for Gerber code generation.
//!
//! All types are stateless, meaning that they contain all information in order
//! to render themselves. This means for example that each `Coordinates`
//! instance contains a reference to the coordinate format to be used.

use std::convert::Into;

use ::{CoordinateFormat, CoordinateNumber};

/// Coordinates are part of an operation.
///
/// Coordinates are modal. If an X is omitted, the X coordinate of the
/// current point is used. Similar for Y.
#[derive(Debug, PartialEq, Eq)]
pub struct Coordinates {
    pub x: Option<CoordinateNumber>,
    pub y: Option<CoordinateNumber>,
    pub format: CoordinateFormat,
}

impl Coordinates {
    pub fn new<T, U>(x: T, y: U, format: CoordinateFormat) -> Self
            where T: Into<CoordinateNumber>, U: Into<CoordinateNumber> {
        Coordinates { x: Some(x.into()), y: Some(y.into()), format: format }
    }

    pub fn at_x<T>(x: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        Coordinates { x: Some(x.into()), y: None, format: format }
    }

    pub fn at_y<T>(y: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        Coordinates { x: None, y: Some(y.into()), format: format }
    }
}

/// Coordinate offsets can be used for interpolate operations in circular
/// interpolation mode.
#[derive(Debug, PartialEq, Eq)]
pub struct CoordinateOffset {
    pub x: Option<CoordinateNumber>,
    pub y: Option<CoordinateNumber>,
    pub format: CoordinateFormat,
}

impl CoordinateOffset {
    pub fn new<T, U>(x: T, y: U, format: CoordinateFormat) -> Self
            where T: Into<CoordinateNumber>, U: Into<CoordinateNumber> {
        CoordinateOffset { x: Some(x.into()), y: Some(y.into()), format: format }
    }

    pub fn at_x<T>(x: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        CoordinateOffset { x: Some(x.into()), y: None, format: format }
    }

    pub fn at_y<T>(y: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        CoordinateOffset { x: None, y: Some(y.into()), format: format }
    }
}

// Root type

#[derive(Debug)]
pub enum Command {
    FunctionCode(FunctionCode),
    ExtendedCode(ExtendedCode),
}

// Main categories

#[derive(Debug)]
pub enum FunctionCode {
    DCode(DCode),
    GCode(GCode),
    MCode(MCode),
}

#[derive(Debug)]
pub enum ExtendedCode {
    /// FS
    CoordinateFormat(CoordinateFormat),
    /// MO
    Unit(Unit),
    /// AD
    ApertureDefinition(ApertureDefinition),
    /// AM
    ApertureMacro(::macros::ApertureMacro),
    /// LP
    LoadPolarity(Polarity),
    /// SR
    StepAndRepeat(StepAndRepeat),
    /// TF
    FileAttribute(::attributes::FileAttribute),
    /// TA
    ApertureAttribute(::attributes::ApertureAttribute),
    /// TD
    DeleteAttribute(String),
}

// Function codes

#[derive(Debug)]
pub enum DCode {
    Operation(Operation),
    SelectAperture(i32),
}

#[derive(Debug)]
pub enum GCode {
    InterpolationMode(InterpolationMode),
    RegionMode(bool),
    QuadrantMode(QuadrantMode),
    Comment(String),
}

#[derive(Debug)]
pub enum MCode {
    EndOfFile,
}

#[derive(Debug)]
pub enum Operation {
    /// D01 Command
    Interpolate(Coordinates, Option<CoordinateOffset>),
    /// D02 Command
    Move(Coordinates),
    /// D03 Command
    Flash(Coordinates),
}

#[derive(Debug)]
pub enum InterpolationMode {
    Linear,
    ClockwiseCircular,
    CounterclockwiseCircular,
}

#[derive(Debug)]
pub enum QuadrantMode {
    Single,
    Multi,
}

// Extended codes

#[derive(Debug)]
pub enum Unit {
    Inches,
    Millimeters,
}

#[derive(Debug)]
pub struct ApertureDefinition {
    pub code: i32,
    pub aperture: Aperture,
}

#[derive(Debug)]
pub enum Aperture {
    Circle(Circle),
    Rectangle(Rectangular),
    Obround(Rectangular),
    Polygon(Polygon),
    Other(String),
}

#[derive(Debug)]
pub struct Circle {
    pub diameter: f64,
    pub hole_diameter: Option<f64>,
}

#[derive(Debug)]
pub struct Rectangular {
    pub x: f64,
    pub y: f64,
    pub hole_diameter: Option<f64>,
}

#[derive(Debug)]
pub struct Polygon {
    pub diameter: f64,
    pub vertices: u8, // 3--12
    pub rotation: Option<f64>,
    pub hole_diameter: Option<f64>,
}

#[derive(Debug)]
pub enum Polarity {
    Clear,
    Dark,
}

#[derive(Debug)]
pub enum StepAndRepeat {
    Open { repeat_x: u32, repeat_y: u32, distance_x: f64, distance_y: f64 },
    Close,
}

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

    use ::{CoordinateNumber, CoordinateFormat};
    use super::*;

    #[test]
    fn test_debug() {
        //! The debug representation should work properly.
        let c = Command::FunctionCode(FunctionCode::GCode(GCode::Comment("test".to_string())));
        let debug = format!("{:?}", c);
        assert_eq!(debug, "FunctionCode(GCode(Comment(\"test\")))");
    }

    #[test]
    fn test_coordinates_into() {
        let cf = CoordinateFormat::new(2, 4);
        let c1 = Coordinates::new(CoordinateNumber::from(1), CoordinateNumber::from(2), cf);
        let c2 = Coordinates::new(1, 2, cf);
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_coordinates_into_mixed() {
        let cf = CoordinateFormat::new(2, 4);
        let c1 = Coordinates::new(CoordinateNumber::from(1), 2, cf);
        let c2 = Coordinates::new(1, 2, cf);
        assert_eq!(c1, c2);
    }

}
<commit_msg>Implement constructors for `Circle` and `Rectangular`<commit_after>//! Types for Gerber code generation.
//!
//! All types are stateless, meaning that they contain all information in order
//! to render themselves. This means for example that each `Coordinates`
//! instance contains a reference to the coordinate format to be used.

use std::convert::Into;

use ::{CoordinateFormat, CoordinateNumber};

/// Coordinates are part of an operation.
///
/// Coordinates are modal. If an X is omitted, the X coordinate of the
/// current point is used. Similar for Y.
#[derive(Debug, PartialEq, Eq)]
pub struct Coordinates {
    pub x: Option<CoordinateNumber>,
    pub y: Option<CoordinateNumber>,
    pub format: CoordinateFormat,
}

impl Coordinates {
    pub fn new<T, U>(x: T, y: U, format: CoordinateFormat) -> Self
            where T: Into<CoordinateNumber>, U: Into<CoordinateNumber> {
        Coordinates { x: Some(x.into()), y: Some(y.into()), format: format }
    }

    pub fn at_x<T>(x: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        Coordinates { x: Some(x.into()), y: None, format: format }
    }

    pub fn at_y<T>(y: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        Coordinates { x: None, y: Some(y.into()), format: format }
    }
}

/// Coordinate offsets can be used for interpolate operations in circular
/// interpolation mode.
#[derive(Debug, PartialEq, Eq)]
pub struct CoordinateOffset {
    pub x: Option<CoordinateNumber>,
    pub y: Option<CoordinateNumber>,
    pub format: CoordinateFormat,
}

impl CoordinateOffset {
    pub fn new<T, U>(x: T, y: U, format: CoordinateFormat) -> Self
            where T: Into<CoordinateNumber>, U: Into<CoordinateNumber> {
        CoordinateOffset { x: Some(x.into()), y: Some(y.into()), format: format }
    }

    pub fn at_x<T>(x: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        CoordinateOffset { x: Some(x.into()), y: None, format: format }
    }

    pub fn at_y<T>(y: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        CoordinateOffset { x: None, y: Some(y.into()), format: format }
    }
}

// Root type

#[derive(Debug)]
pub enum Command {
    FunctionCode(FunctionCode),
    ExtendedCode(ExtendedCode),
}

// Main categories

#[derive(Debug)]
pub enum FunctionCode {
    DCode(DCode),
    GCode(GCode),
    MCode(MCode),
}

#[derive(Debug)]
pub enum ExtendedCode {
    /// FS
    CoordinateFormat(CoordinateFormat),
    /// MO
    Unit(Unit),
    /// AD
    ApertureDefinition(ApertureDefinition),
    /// AM
    ApertureMacro(::macros::ApertureMacro),
    /// LP
    LoadPolarity(Polarity),
    /// SR
    StepAndRepeat(StepAndRepeat),
    /// TF
    FileAttribute(::attributes::FileAttribute),
    /// TA
    ApertureAttribute(::attributes::ApertureAttribute),
    /// TD
    DeleteAttribute(String),
}

// Function codes

#[derive(Debug)]
pub enum DCode {
    Operation(Operation),
    SelectAperture(i32),
}

#[derive(Debug)]
pub enum GCode {
    InterpolationMode(InterpolationMode),
    RegionMode(bool),
    QuadrantMode(QuadrantMode),
    Comment(String),
}

#[derive(Debug)]
pub enum MCode {
    EndOfFile,
}

#[derive(Debug)]
pub enum Operation {
    /// D01 Command
    Interpolate(Coordinates, Option<CoordinateOffset>),
    /// D02 Command
    Move(Coordinates),
    /// D03 Command
    Flash(Coordinates),
}

#[derive(Debug)]
pub enum InterpolationMode {
    Linear,
    ClockwiseCircular,
    CounterclockwiseCircular,
}

#[derive(Debug)]
pub enum QuadrantMode {
    Single,
    Multi,
}

// Extended codes

#[derive(Debug)]
pub enum Unit {
    Inches,
    Millimeters,
}

#[derive(Debug)]
pub struct ApertureDefinition {
    pub code: i32,
    pub aperture: Aperture,
}

#[derive(Debug, PartialEq)]
pub enum Aperture {
    Circle(Circle),
    Rectangle(Rectangular),
    Obround(Rectangular),
    Polygon(Polygon),
    Other(String),
}

#[derive(Debug, PartialEq)]
pub struct Circle {
    pub diameter: f64,
    pub hole_diameter: Option<f64>,
}

impl Circle {
    pub fn new(diameter: f64) -> Self {
        Circle {
            diameter: diameter,
            hole_diameter: None,
        }
    }

    pub fn with_hole(diameter: f64, hole_diameter: f64) -> Self {
        Circle {
            diameter: diameter,
            hole_diameter: Some(hole_diameter),
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct Rectangular {
    pub x: f64,
    pub y: f64,
    pub hole_diameter: Option<f64>,
}

impl Rectangular {
    pub fn new(x: f64, y: f64) -> Self {
        Rectangular {
            x: x,
            y: y,
            hole_diameter: None,
        }
    }

    pub fn with_hole(x: f64, y: f64, hole_diameter: f64) -> Self {
        Rectangular {
            x: x,
            y: y,
            hole_diameter: Some(hole_diameter),
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct Polygon {
    pub diameter: f64,
    pub vertices: u8, // 3--12
    pub rotation: Option<f64>,
    pub hole_diameter: Option<f64>,
}

#[derive(Debug)]
pub enum Polarity {
    Clear,
    Dark,
}

#[derive(Debug)]
pub enum StepAndRepeat {
    Open { repeat_x: u32, repeat_y: u32, distance_x: f64, distance_y: f64 },
    Close,
}

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

    use ::{CoordinateNumber, CoordinateFormat};
    use super::*;

    #[test]
    fn test_debug() {
        //! The debug representation should work properly.
        let c = Command::FunctionCode(FunctionCode::GCode(GCode::Comment("test".to_string())));
        let debug = format!("{:?}", c);
        assert_eq!(debug, "FunctionCode(GCode(Comment(\"test\")))");
    }

    #[test]
    fn test_coordinates_into() {
        let cf = CoordinateFormat::new(2, 4);
        let c1 = Coordinates::new(CoordinateNumber::from(1), CoordinateNumber::from(2), cf);
        let c2 = Coordinates::new(1, 2, cf);
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_coordinates_into_mixed() {
        let cf = CoordinateFormat::new(2, 4);
        let c1 = Coordinates::new(CoordinateNumber::from(1), 2, cf);
        let c2 = Coordinates::new(1, 2, cf);
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_circle_new() {
        let c1 = Circle::new(3.0);
        let c2 = Circle { diameter: 3.0, hole_diameter: None };
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_circle_with_hole() {
        let c1 = Circle::with_hole(3.0, 1.0);
        let c2 = Circle { diameter: 3.0, hole_diameter: Some(1.0) };
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_rectangular_new() {
        let r1 = Rectangular::new(2.0, 3.0);
        let r2 = Rectangular { x: 2.0, y: 3.0, hole_diameter: None };
        assert_eq!(r1, r2);
    }

    #[test]
    fn test_rectangular_with_hole() {
        let r1 = Rectangular::with_hole(3.0, 2.0, 1.0);
        let r2 = Rectangular { x: 3.0, y: 2.0, hole_diameter: Some(1.0) };
        assert_eq!(r1, r2);
    }

}
<|endoftext|>