<commit_before>/*
 * The component library for Fractalide
 *
 * Author : Denis Michiels
 * Copyright (C) 2015 Michiels Denis
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

use std::collections::HashMap;

use std::sync::mpsc::{SyncSender, Sender, Receiver, SendError, RecvError};
use std::sync::mpsc::sync_channel;
use std::sync::mpsc::channel;

use std::thread;
use std::mem;

/*
 * Input Ports for the state, only the receivers
 */

pub enum InputPortError {
    InputPortNotFind(&'static str),
    CannotRecv(RecvError),
}

pub struct InputPorts {
    input: HashMap<&'static str, Receiver<i32>>,
}

impl InputPorts {

    fn new() -> Self {
        InputPorts { input: HashMap::new(), }
    }

    fn add(&mut self, name: &'static str, rec: Receiver<i32>) -> Option<Receiver<i32>> {
        self.input.insert(name, rec)
    }

    fn remove(&mut self, name: &'static str) -> Option<Receiver<i32>> {
        self.input.remove(&name)
    }

    pub fn recv(&self, name: &'static str) -> Result<i32, InputPortError> {
        let port = self.input.get(name);
        match port {
            None => { Err(InputPortError::InputPortNotFind(name)) }
            Some(port) => {
                match port.recv() {
                    Ok(msg) => { Ok(msg) },
                    Err(err) => { Err(InputPortError::CannotRecv(err)) },
                }
            }
        }
    }

}

#[test]
fn input_ports_tests() {
   let mut input = InputPorts::new();
   let (tx, rx) = sync_channel(16);
   input.add("input", rx);
   tx.send(42).unwrap();
   let result = input.recv("input").ok().expect("There is no message in the channel");
   assert_eq!(result, 42);
   let recv = input.remove("input");
   assert!(recv.is_some());
   let recv = input.remove("input");
   assert!(recv.is_none());
   let result = input.recv("input");
   assert!(result.is_err());
}

/*
 * Output Ports for the state
 */

pub enum OutputPortError {
    OutputPortNotFind(&'static str),
    CannotSend(SendError<i32>),
}

pub struct OutputPorts {
    output: HashMap<&'static str, Option<SyncSender<i32>>>,
}

impl OutputPorts {
    fn new() -> Self {
        OutputPorts { output: HashMap::new(), }
    }

    fn add(&mut self, name: &'static str) -> Option<Option<SyncSender<i32>>>{
        self.output.insert(name, None)
    }

    fn remove(&mut self, name: &'static str) -> Option<Option<SyncSender<i32>>> {
        self.output.remove(name)
    }

    fn connect(&mut self, name: &'static str, send: SyncSender<i32>) -> Result<(), OutputPortError> {
        if !self.output.contains_key(name) {
            Err(OutputPortError::OutputPortNotFind(name))
        } else {
            self.output.insert(name, Some(send));
            Ok(())
        }
    }

    pub fn send(&self, name: &'static str, msg: i32) -> Result<(), OutputPortError> {
        let sender = self.output.get(name);
        match sender {
            None => { Err(OutputPortError::OutputPortNotFind(name)) },
            Some(port) => {
                match *port {
                    None => { Ok(()) },
                    Some(ref send) => {
                        let res = send.send(msg);
                        if res.is_ok() { Ok(()) }
                        else { Err(OutputPortError::CannotSend(res.unwrap_err())) }
                    }
                }
            }
        }
    }

}

#[test]
fn output_ports_tests() {
   let mut output = OutputPorts::new();
   let (tx, rx) = sync_channel(16);
   let res = output.send("output", 42);
   assert!(res.is_err());
   let res = output.connect("output", tx.clone());
   assert!(res.is_err());
   output.add("output");
   let res = output.remove("output");
   assert!(res.is_some());
   let res = output.remove("output");
   assert!(res.is_none());

   output.add("output");
   output.connect("output", tx);
   output.send("output", 42);
   let res = rx.recv().unwrap();
   assert_eq!(res, 42);
}

#[test]
fn input_output_ports_tests() {
    let mut input = InputPorts::new();
    let mut output = OutputPorts::new();
    let (tx, rx) = sync_channel(16);
    input.add("input", rx);
    output.add("output");
    output.connect("output", tx);
    output.send("output", 42);
    assert_eq!(input.recv("input").ok().expect(""), 42);
}

/*
 * Component Structure
 * Divided in two : component and state.
 * The component is the user interface for the component.
 * The state is the running part of the component, in a Thread.
 * The two use a channel to interact.
 */

pub trait Closure {
    fn run(&mut self, input_ports: &InputPorts, output_ports: &OutputPorts);
}

pub type BoxedClosure = Box<Closure + Send>;

enum CompMsg {
    Start, Stop, Halt,
    RunEnd(BoxedClosure, InputPorts, OutputPorts),
    ConnectOutputPort(&'static str, SyncSender<i32>),
    AddInputPort(&'static str, Receiver<i32>),
    AddOutputPort(&'static str),
}

enum CompError {
    PortNotFound(&'static str),
}

pub struct Component {
    sender: Sender<CompMsg>,
    input_senders: HashMap<&'static str, SyncSender<i32>>,
}

impl Component {
    pub fn new<T: Closure + Send + 'static>(c: Box<T>) -> Self {
        let (control_s, control_r) = channel();
        {
            let control_sender = control_s.clone();
            let mut state = State::new(c, control_sender);
            thread::spawn(move || {
                loop {
                    let msg = control_r.recv().unwrap();
                    match msg {
                        CompMsg::Start => { state.start(); },
                        CompMsg::Stop => { state.stop(); },
                        CompMsg::Halt => { break; },
                        CompMsg::RunEnd(closure, inputs, outputs)  => { state.run_end(closure, inputs, outputs); },
                        CompMsg::AddInputPort(name, rec) => { state.add_input_port(name, rec); },
                        CompMsg::AddOutputPort(name) => { state.add_output_port(name); },
                        CompMsg::ConnectOutputPort(port, send) => { state.connect_output_port(port, send); },
                    }
                }
            });
        }
        Component {
            sender: control_s,
            input_senders: HashMap::new(),
        }
    }

    pub fn add_input_port(&mut self, name: &'static str) {
        let (tx, rx) = sync_channel(16);
        self.input_senders.insert(name, tx);
        self.sender.send(CompMsg::AddInputPort(name, rx)).unwrap();
    }

    pub fn add_output_port(&mut self, name: &'static str) {
        self.sender.send(CompMsg::AddOutputPort(name)).unwrap();
    }

    pub fn connect_output_port(&mut self, name: &'static str, rec: &Component, dest: &'static str) {
        let s = rec.get_sender(dest);
        if let Some(s) = s {
            self.sender.send(CompMsg::ConnectOutputPort(name, s)).unwrap();
        }
    }

    pub fn start(&self) {
        self.sender.send(CompMsg::Start).unwrap();
    }

    pub fn get_sender(&self, name: &'static str) -> Option<SyncSender<i32>> {
        match self.input_senders.get(name) {
            None => { None },
            Some(s) => {
                Some(s.clone())
            }
        }
    }
}

struct State {
    control_sender:Sender<CompMsg>,
    closure: Option<BoxedClosure>,
    in_receivers: Option<InputPorts>,
    out_senders: Option<OutputPorts>,
}

impl State {
    fn new(c: BoxedClosure, cs: Sender<CompMsg>) -> Self {
        State {
            control_sender: cs,
            closure: Some(c),
            in_receivers: Some(InputPorts::new()),
            out_senders: Some(OutputPorts::new()),
        }
    }

    fn add_input_port(&mut self, name: &'static str, rec: Receiver<i32>) {
        if let Some(ref mut inputs) = self.in_receivers {
            inputs.add(name, rec);
        }
    }

    fn add_output_port(&mut self, name: &'static str) {
        if let Some(ref mut outputs) = self.out_senders {
            outputs.add(name);
        }
    }

    fn connect_output_port(&mut self, port: &'static str, send: SyncSender<i32>) {
        if let Some(ref mut out_s) = self.out_senders {
            out_s.connect(port, send);
        }
    }

    fn start(&mut self) { self.run(); }

    fn stop(&mut self) { }

    fn run_end(&mut self, c: BoxedClosure, i: InputPorts, o: OutputPorts) {
        self.closure = Some(c);
        self.in_receivers = Some(i);
        self.out_senders = Some(o);
        self.run();
    }

    fn run(&mut self) {
        let mut c = mem::replace(&mut self.closure, None).unwrap();
        let inputs = mem::replace(&mut self.in_receivers, None).unwrap();
        let outputs = mem::replace(&mut self.out_senders, None).unwrap();
        let control_sender = self.control_sender.clone();

        thread::spawn(move || {
            c.run(&inputs, &outputs);
            control_sender.send(CompMsg::RunEnd(c, inputs, outputs)).unwrap();
        });
    }
}
<commit_msg>Allow dynamic edition of the component<commit_after>/*
 * The component library for Fractalide
 *
 * Author : Denis Michiels
 * Copyright (C) 2015 Michiels Denis
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

use std::collections::HashMap;

use std::sync::mpsc::{SyncSender, Sender, Receiver, SendError, RecvError};
use std::sync::mpsc::sync_channel;
use std::sync::mpsc::channel;

use std::thread;
use std::mem;

/*
 * Input Ports for the state, only the receivers
 */

pub enum InputPortError {
    InputPortNotFind(&'static str),
    CannotRecv(RecvError),
}

pub struct InputPorts {
    input: HashMap<&'static str, Receiver<i32>>,
}

impl InputPorts {

    fn new() -> Self {
        InputPorts { input: HashMap::new(), }
    }

    fn add(&mut self, name: &'static str, rec: Receiver<i32>) -> Option<Receiver<i32>> {
        self.input.insert(name, rec)
    }

    fn remove(&mut self, name: &'static str) -> Option<Receiver<i32>> {
        self.input.remove(&name)
    }

    pub fn recv(&self, name: &'static str) -> Result<i32, InputPortError> {
        let port = self.input.get(name);
        match port {
            None => { Err(InputPortError::InputPortNotFind(name)) }
            Some(port) => {
                match port.recv() {
                    Ok(msg) => { Ok(msg) },
                    Err(err) => { Err(InputPortError::CannotRecv(err)) },
                }
            }
        }
    }

}

#[test]
fn input_ports_tests() {
   let mut input = InputPorts::new();
   let (tx, rx) = sync_channel(16);
   input.add("input", rx);
   tx.send(42).unwrap();
   let result = input.recv("input").ok().expect("There is no message in the channel");
   assert_eq!(result, 42);
   let recv = input.remove("input");
   assert!(recv.is_some());
   let recv = input.remove("input");
   assert!(recv.is_none());
   let result = input.recv("input");
   assert!(result.is_err());
}

/*
 * Output Ports for the state
 */

pub enum OutputPortError {
    OutputPortNotFind(&'static str),
    CannotSend(SendError<i32>),
}

pub struct OutputPorts {
    output: HashMap<&'static str, Option<SyncSender<i32>>>,
}

impl OutputPorts {
    fn new() -> Self {
        OutputPorts { output: HashMap::new(), }
    }

    fn add(&mut self, name: &'static str) -> Option<Option<SyncSender<i32>>>{
        self.output.insert(name, None)
    }

    fn remove(&mut self, name: &'static str) -> Option<Option<SyncSender<i32>>> {
        self.output.remove(name)
    }

    fn connect(&mut self, name: &'static str, send: SyncSender<i32>) -> Result<(), OutputPortError> {
        if !self.output.contains_key(name) {
            Err(OutputPortError::OutputPortNotFind(name))
        } else {
            self.output.insert(name, Some(send));
            Ok(())
        }
    }

    pub fn send(&self, name: &'static str, msg: i32) -> Result<(), OutputPortError> {
        let sender = self.output.get(name);
        match sender {
            None => { Err(OutputPortError::OutputPortNotFind(name)) },
            Some(port) => {
                match *port {
                    None => { Ok(()) },
                    Some(ref send) => {
                        let res = send.send(msg);
                        if res.is_ok() { Ok(()) }
                        else { Err(OutputPortError::CannotSend(res.unwrap_err())) }
                    }
                }
            }
        }
    }

}

#[test]
fn output_ports_tests() {
   let mut output = OutputPorts::new();
   let (tx, rx) = sync_channel(16);
   let res = output.send("output", 42);
   assert!(res.is_err());
   let res = output.connect("output", tx.clone());
   assert!(res.is_err());
   output.add("output");
   let res = output.remove("output");
   assert!(res.is_some());
   let res = output.remove("output");
   assert!(res.is_none());

   output.add("output");
   output.connect("output", tx);
   output.send("output", 42);
   let res = rx.recv().unwrap();
   assert_eq!(res, 42);
}

#[test]
fn input_output_ports_tests() {
    let mut input = InputPorts::new();
    let mut output = OutputPorts::new();
    let (tx, rx) = sync_channel(16);
    input.add("input", rx);
    output.add("output");
    output.connect("output", tx);
    output.send("output", 42);
    assert_eq!(input.recv("input").ok().expect(""), 42);
}

/*
 * Component Structure
 * Divided in two : component and state.
 * The component is the user interface for the component.
 * The state is the running part of the component, in a Thread.
 * The two use a channel to interact.
 */

pub trait Closure {
    fn run(&mut self, input_ports: &InputPorts, output_ports: &OutputPorts);
}

pub type BoxedClosure = Box<Closure + Send>;

enum CompMsg {
    Start, Stop, Halt,
    RunEnd(BoxedClosure, InputPorts, OutputPorts),
    ConnectOutputPort(&'static str, SyncSender<i32>),
    AddInputPort(&'static str, Receiver<i32>),
    AddOutputPort(&'static str),
}

enum CompError {
    PortNotFound(&'static str),
}

pub struct Component {
    sender: Sender<CompMsg>,
    input_senders: HashMap<&'static str, SyncSender<i32>>,
}

impl Component {
    pub fn new<T: Closure + Send + 'static>(c: Box<T>) -> Self {
        let (control_s, control_r) = channel();
        {
            let control_sender = control_s.clone();
            let mut state = State::new(c, control_sender);
            thread::spawn(move || {
                loop {
                    let msg = control_r.recv().unwrap();
                    match msg {
                        CompMsg::Start => { state.start(); },
                        CompMsg::Stop => { state.stop(); },
                        CompMsg::Halt => { break; },
                        CompMsg::RunEnd(closure, inputs, outputs)  => { state.run_end(closure, inputs, outputs); },
                        CompMsg::AddInputPort(name, rec) => { state.receive_edit_msg(CompMsg::AddInputPort(name, rec)); },
                        CompMsg::AddOutputPort(name) => { state.receive_edit_msg(CompMsg::AddOutputPort(name)); },
                        CompMsg::ConnectOutputPort(port, send) => { state.receive_edit_msg(CompMsg::ConnectOutputPort(port, send)); },
                    }
                }
            });
        }
        Component {
            sender: control_s,
            input_senders: HashMap::new(),
        }
    }

    pub fn add_input_port(&mut self, name: &'static str) {
        let (tx, rx) = sync_channel(16);
        self.input_senders.insert(name, tx);
        self.sender.send(CompMsg::AddInputPort(name, rx)).unwrap();
    }

    pub fn add_output_port(&mut self, name: &'static str) {
        self.sender.send(CompMsg::AddOutputPort(name)).unwrap();
    }

    pub fn connect_output_port(&mut self, name: &'static str, rec: &Component, dest: &'static str) {
        let s = rec.get_sender(dest);
        if let Some(s) = s {
            self.sender.send(CompMsg::ConnectOutputPort(name, s)).unwrap();
        }
    }

    pub fn start(&self) {
        self.sender.send(CompMsg::Start).unwrap();
    }

    pub fn get_sender(&self, name: &'static str) -> Option<SyncSender<i32>> {
        match self.input_senders.get(name) {
            None => { None },
            Some(s) => {
                Some(s.clone())
            }
        }
    }
}

struct State {
    control_sender:Sender<CompMsg>,
    closure: Option<BoxedClosure>,
    in_receivers: Option<InputPorts>,
    out_senders: Option<OutputPorts>,
    can_run: bool,
    edit_msgs: Vec<CompMsg>,
}

impl State {
    fn new(c: BoxedClosure, cs: Sender<CompMsg>) -> Self {
        State {
            control_sender: cs,
            closure: Some(c),
            in_receivers: Some(InputPorts::new()),
            out_senders: Some(OutputPorts::new()),
            can_run: false,
            edit_msgs: vec![],
        }
    }

    fn edit_component(&mut self, msg: CompMsg){
        match msg {
            CompMsg::AddInputPort(name, rec) => {
                self.in_receivers.as_mut().unwrap().add(name, rec);
            },
            CompMsg::AddOutputPort(name) => {
                self.out_senders.as_mut().unwrap().add(name);
            },
            CompMsg::ConnectOutputPort(name, send) => {
                self.out_senders.as_mut().unwrap().connect(name, send);
            },
            _ => { },
        }

    }

    fn receive_edit_msg(&mut self, msg: CompMsg){
        if self.can_run {
            self.edit_msgs.push(msg);
        } else {
            self.edit_component(msg);
        }
    }

    fn start(&mut self) {
        if !self.can_run {
            self.can_run = true;
            self.run();
        }
    }

    fn stop(&mut self) {
        self.can_run = false;
    }

    fn run_end(&mut self, c: BoxedClosure, i: InputPorts, o: OutputPorts) {
        self.closure = Some(c);
        self.in_receivers = Some(i);
        self.out_senders = Some(o);
        let msgs = mem::replace(&mut self.edit_msgs, vec![]);
        for msg in msgs {
            self.edit_component(msg);
        }
        if self.can_run {
            self.run();
        }
    }

    fn run(&mut self) {
        let mut c = mem::replace(&mut self.closure, None).unwrap();
        let inputs = mem::replace(&mut self.in_receivers, None).unwrap();
        let outputs = mem::replace(&mut self.out_senders, None).unwrap();
        let control_sender = self.control_sender.clone();

        thread::spawn(move || {
            c.run(&inputs, &outputs);
            control_sender.send(CompMsg::RunEnd(c, inputs, outputs)).unwrap();
        });
    }
}

#[test]
fn edit_state_tests() {
    struct Test;
    impl Closure for Test {
        fn run(&mut self, input: &InputPorts, output: &OutputPorts){
        }
    }
    let (tx, rx) = channel();
    let mut state = State::new(Box::new(Test), tx);

    // Add while not running
    assert!(state.edit_msgs.len() == 0);
    state.receive_edit_msg(CompMsg::AddOutputPort("input"));
    assert!(state.edit_msgs.len() == 0);
    assert!(state.out_senders.as_mut().unwrap().output.len() == 1);

    // Add while running
    state.start();
    state.receive_edit_msg(CompMsg::AddOutputPort("input2"));
    // Must save the msg
    assert!(state.edit_msgs.len() == 1);
    assert!(state.out_senders.is_none());
    // At the end, the msg must read. As the closure run again, we have
    // no access to the out_senders
    state.run_end(Box::new(Test), InputPorts::new(), OutputPorts::new());
    assert!(state.edit_msgs.len() == 0);
    assert!(state.out_senders.is_none());

    // Add after stop
    state.receive_edit_msg(CompMsg::AddOutputPort("input3"));
    state.stop();
    state.run_end(Box::new(Test), InputPorts::new(), OutputPorts::new());
    assert!(state.edit_msgs.len() == 0);
    assert!(state.out_senders.as_mut().unwrap().output.len() == 1);

    // receive useless msgs
    rx.recv();
    rx.recv();

}
<|endoftext|>


<commit_before>//! Error types.

use std::error;
use std::convert::From;
use std::fmt;
use std::io;
use std::result;
use std::collections::HashMap;

pub use self::sqlstate::SqlState;
use {Result, DbErrorNew};

mod sqlstate;

/// A Postgres error or notice.
#[derive(Clone, PartialEq, Eq)]
pub struct DbError {
    /// The field contents are ERROR, FATAL, or PANIC (in an error message),
    /// or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message), or a
    /// localized translation of one of these.
    pub severity: String,

    /// The SQLSTATE code for the error.
    pub code: SqlState,

    /// The primary human-readable error message. This should be accurate but
    /// terse (typically one line).
    pub message: String,

    /// An optional secondary error message carrying more detail about the
    /// problem. Might run to multiple lines.
    pub detail: Option<String>,

    /// An optional suggestion what to do about the problem. This is intended
    /// to differ from Detail in that it offers advice (potentially
    /// inappropriate) rather than hard facts. Might run to multiple lines.
    pub hint: Option<String>,

    /// An optional error cursor position into either the original query string
    /// or an internally generated query.
    pub position: Option<ErrorPosition>,

    /// An indication of the context in which the error occurred. Presently
    /// this includes a call stack traceback of active procedural language
    /// functions and internally-generated queries. The trace is one entry per
    /// line, most recent first.
    pub where_: Option<String>,

    /// If the error was associated with a specific database object, the name
    /// of the schema containing that object, if any. (PostgreSQL 9.3+)
    pub schema: Option<String>,

    /// If the error was associated with a specific table, the name of the
    /// table. (Refer to the schema name field for the name of the table's
    /// schema.) (PostgreSQL 9.3+)
    pub table: Option<String>,

    /// If the error was associated with a specific table column, the name of
    /// the column. (Refer to the schema and table name fields to identify the
    /// table.) (PostgreSQL 9.3+)
    pub column: Option<String>,

    /// If the error was associated with a specific data type, the name of the
    /// data type. (Refer to the schema name field for the name of the data
    /// type's schema.) (PostgreSQL 9.3+)
    pub datatype: Option<String>,

    /// If the error was associated with a specific constraint, the name of the
    /// constraint. Refer to fields listed above for the associated table or
    /// domain. (For this purpose, indexes are treated as constraints, even if
    /// they weren't created with constraint syntax.) (PostgreSQL 9.3+)
    pub constraint: Option<String>,

    /// The file name of the source-code location where the error was reported.
    pub file: String,

    /// The line number of the source-code location where the error was
    /// reported.
    pub line: u32,

    /// The name of the source-code routine reporting the error.
    pub routine: String,

    _p: (),
}

impl DbErrorNew for DbError {
    fn new_raw(fields: Vec<(u8, String)>) -> result::Result<DbError, ()> {
        let mut map: HashMap<_, _> = fields.into_iter().collect();
        Ok(DbError {
            severity: try!(map.remove(&b'S').ok_or(())),
            code: SqlState::from_code(try!(map.remove(&b'C').ok_or(()))),
            message: try!(map.remove(&b'M').ok_or(())),
            detail: map.remove(&b'D'),
            hint: map.remove(&b'H'),
            position: match map.remove(&b'P') {
                Some(pos) => Some(ErrorPosition::Normal(try!(pos.parse().map_err(|_| ())))),
                None => {
                    match map.remove(&b'p') {
                        Some(pos) => {
                            Some(ErrorPosition::Internal {
                                position: try!(pos.parse().map_err(|_| ())),
                                query: try!(map.remove(&b'q').ok_or(())),
                            })
                        }
                        None => None,
                    }
                }
            },
            where_: map.remove(&b'W'),
            schema: map.remove(&b's'),
            table: map.remove(&b't'),
            column: map.remove(&b'c'),
            datatype: map.remove(&b'd'),
            constraint: map.remove(&b'n'),
            file: try!(map.remove(&b'F').ok_or(())),
            line: try!(map.remove(&b'L').and_then(|l| l.parse().ok()).ok_or(())),
            routine: try!(map.remove(&b'R').ok_or(())),
            _p: (),
        })
    }

    fn new_connect<T>(fields: Vec<(u8, String)>) -> result::Result<T, ConnectError> {
        match DbError::new_raw(fields) {
            Ok(err) => Err(ConnectError::Db(Box::new(err))),
            Err(()) => Err(ConnectError::Io(::bad_response())),
        }
    }

    fn new<T>(fields: Vec<(u8, String)>) -> Result<T> {
        match DbError::new_raw(fields) {
            Ok(err) => Err(Error::Db(Box::new(err))),
            Err(()) => Err(Error::Io(::bad_response())),
        }
    }
}

// manual impl to leave out _p
impl fmt::Debug for DbError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("DbError")
           .field("severity", &self.severity)
           .field("code", &self.code)
           .field("message", &self.message)
           .field("detail", &self.detail)
           .field("hint", &self.hint)
           .field("position", &self.position)
           .field("where_", &self.where_)
           .field("schema", &self.schema)
           .field("table", &self.table)
           .field("column", &self.column)
           .field("datatype", &self.datatype)
           .field("constraint", &self.constraint)
           .field("file", &self.file)
           .field("line", &self.line)
           .field("routine", &self.routine)
           .finish()
    }
}

impl fmt::Display for DbError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}: {}", self.severity, self.message)
    }
}

impl error::Error for DbError {
    fn description(&self) -> &str {
        &self.message
    }
}

/// Reasons a new Postgres connection could fail.
#[derive(Debug)]
pub enum ConnectError {
    /// An error relating to connection parameters.
    ConnectParams(Box<error::Error + Sync + Send>),
    /// An error from the Postgres server itself.
    Db(Box<DbError>),
    /// An error initializing the SSL session.
    Ssl(Box<error::Error + Sync + Send>),
    /// An error communicating with the server.
    Io(io::Error),
}

impl fmt::Display for ConnectError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(fmt.write_str(error::Error::description(self)));
        match *self {
            ConnectError::ConnectParams(ref msg) => write!(fmt, ": {}", msg),
            ConnectError::Db(ref err) => write!(fmt, ": {}", err),
            ConnectError::Ssl(ref err) => write!(fmt, ": {}", err),
            ConnectError::Io(ref err) => write!(fmt, ": {}", err),
        }
    }
}

impl error::Error for ConnectError {
    fn description(&self) -> &str {
        match *self {
            ConnectError::ConnectParams(_) => "Invalid connection parameters",
            ConnectError::Db(_) => "Error reported by Postgres",
            ConnectError::Ssl(_) => "Error initiating SSL session",
            ConnectError::Io(_) => "Error communicating with the server",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ConnectError::ConnectParams(ref err) | ConnectError::Ssl(ref err) => Some(&**err),
            ConnectError::Db(ref err) => Some(&**err),
            ConnectError::Io(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for ConnectError {
    fn from(err: io::Error) -> ConnectError {
        ConnectError::Io(err)
    }
}

impl From<DbError> for ConnectError {
    fn from(err: DbError) -> ConnectError {
        ConnectError::Db(Box::new(err))
    }
}

/// Represents the position of an error in a query.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ErrorPosition {
    /// A position in the original query.
    Normal(u32),
    /// A position in an internally generated query.
    Internal {
        /// The byte position.
        position: u32,
        /// A query generated by the Postgres server.
        query: String,
    },
}

/// An error encountered when communicating with the Postgres server.
#[derive(Debug)]
pub enum Error {
    /// An error reported by the Postgres server.
    Db(Box<DbError>),
    /// An error communicating with the Postgres server.
    Io(io::Error),
    /// An error converting between Postgres and Rust types.
    Conversion(Box<error::Error + Sync + Send>),
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(fmt.write_str(error::Error::description(self)));
        match *self {
            Error::Db(ref err) => write!(fmt, ": {}", err),
            Error::Io(ref err) => write!(fmt, ": {}", err),
            Error::Conversion(ref err) => write!(fmt, ": {}", err),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Db(_) => "Error reported by Postgres",
            Error::Io(_) => "Error communicating with the server",
            Error::Conversion(_) => "Error converting between Postgres and Rust types",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Db(ref err) => Some(&**err),
            Error::Io(ref err) => Some(err),
            Error::Conversion(ref err) => Some(&**err),
        }
    }
}

impl From<DbError> for Error {
    fn from(err: DbError) -> Error {
        Error::Db(Box::new(err))
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<Error> for io::Error {
    fn from(err: Error) -> io::Error {
        io::Error::new(io::ErrorKind::Other, err)
    }
}
<commit_msg>Make line/file/routine in Error optional<commit_after>//! Error types.

use std::error;
use std::convert::From;
use std::fmt;
use std::io;
use std::result;
use std::collections::HashMap;

pub use self::sqlstate::SqlState;
use {Result, DbErrorNew};

mod sqlstate;

/// A Postgres error or notice.
#[derive(Clone, PartialEq, Eq)]
pub struct DbError {
    /// The field contents are ERROR, FATAL, or PANIC (in an error message),
    /// or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message), or a
    /// localized translation of one of these.
    pub severity: String,

    /// The SQLSTATE code for the error.
    pub code: SqlState,

    /// The primary human-readable error message. This should be accurate but
    /// terse (typically one line).
    pub message: String,

    /// An optional secondary error message carrying more detail about the
    /// problem. Might run to multiple lines.
    pub detail: Option<String>,

    /// An optional suggestion what to do about the problem. This is intended
    /// to differ from Detail in that it offers advice (potentially
    /// inappropriate) rather than hard facts. Might run to multiple lines.
    pub hint: Option<String>,

    /// An optional error cursor position into either the original query string
    /// or an internally generated query.
    pub position: Option<ErrorPosition>,

    /// An indication of the context in which the error occurred. Presently
    /// this includes a call stack traceback of active procedural language
    /// functions and internally-generated queries. The trace is one entry per
    /// line, most recent first.
    pub where_: Option<String>,

    /// If the error was associated with a specific database object, the name
    /// of the schema containing that object, if any. (PostgreSQL 9.3+)
    pub schema: Option<String>,

    /// If the error was associated with a specific table, the name of the
    /// table. (Refer to the schema name field for the name of the table's
    /// schema.) (PostgreSQL 9.3+)
    pub table: Option<String>,

    /// If the error was associated with a specific table column, the name of
    /// the column. (Refer to the schema and table name fields to identify the
    /// table.) (PostgreSQL 9.3+)
    pub column: Option<String>,

    /// If the error was associated with a specific data type, the name of the
    /// data type. (Refer to the schema name field for the name of the data
    /// type's schema.) (PostgreSQL 9.3+)
    pub datatype: Option<String>,

    /// If the error was associated with a specific constraint, the name of the
    /// constraint. Refer to fields listed above for the associated table or
    /// domain. (For this purpose, indexes are treated as constraints, even if
    /// they weren't created with constraint syntax.) (PostgreSQL 9.3+)
    pub constraint: Option<String>,

    /// The file name of the source-code location where the error was reported.
    pub file: Option<String>,

    /// The line number of the source-code location where the error was
    /// reported.
    pub line: Option<u32>,

    /// The name of the source-code routine reporting the error.
    pub routine: Option<String>,

    _p: (),
}

impl DbErrorNew for DbError {
    fn new_raw(fields: Vec<(u8, String)>) -> result::Result<DbError, ()> {
        let mut map: HashMap<_, _> = fields.into_iter().collect();
        Ok(DbError {
            severity: try!(map.remove(&b'S').ok_or(())),
            code: SqlState::from_code(try!(map.remove(&b'C').ok_or(()))),
            message: try!(map.remove(&b'M').ok_or(())),
            detail: map.remove(&b'D'),
            hint: map.remove(&b'H'),
            position: match map.remove(&b'P') {
                Some(pos) => Some(ErrorPosition::Normal(try!(pos.parse().map_err(|_| ())))),
                None => {
                    match map.remove(&b'p') {
                        Some(pos) => {
                            Some(ErrorPosition::Internal {
                                position: try!(pos.parse().map_err(|_| ())),
                                query: try!(map.remove(&b'q').ok_or(())),
                            })
                        }
                        None => None,
                    }
                }
            },
            where_: map.remove(&b'W'),
            schema: map.remove(&b's'),
            table: map.remove(&b't'),
            column: map.remove(&b'c'),
            datatype: map.remove(&b'd'),
            constraint: map.remove(&b'n'),
            file: map.remove(&b'F'),
            line: map.remove(&b'L').and_then(|l| l.parse().ok()),
            routine: map.remove(&b'R'),
            _p: (),
        })
    }

    fn new_connect<T>(fields: Vec<(u8, String)>) -> result::Result<T, ConnectError> {
        match DbError::new_raw(fields) {
            Ok(err) => Err(ConnectError::Db(Box::new(err))),
            Err(()) => Err(ConnectError::Io(::bad_response())),
        }
    }

    fn new<T>(fields: Vec<(u8, String)>) -> Result<T> {
        match DbError::new_raw(fields) {
            Ok(err) => Err(Error::Db(Box::new(err))),
            Err(()) => Err(Error::Io(::bad_response())),
        }
    }
}

// manual impl to leave out _p
impl fmt::Debug for DbError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("DbError")
           .field("severity", &self.severity)
           .field("code", &self.code)
           .field("message", &self.message)
           .field("detail", &self.detail)
           .field("hint", &self.hint)
           .field("position", &self.position)
           .field("where_", &self.where_)
           .field("schema", &self.schema)
           .field("table", &self.table)
           .field("column", &self.column)
           .field("datatype", &self.datatype)
           .field("constraint", &self.constraint)
           .field("file", &self.file)
           .field("line", &self.line)
           .field("routine", &self.routine)
           .finish()
    }
}

impl fmt::Display for DbError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}: {}", self.severity, self.message)
    }
}

impl error::Error for DbError {
    fn description(&self) -> &str {
        &self.message
    }
}

/// Reasons a new Postgres connection could fail.
#[derive(Debug)]
pub enum ConnectError {
    /// An error relating to connection parameters.
    ConnectParams(Box<error::Error + Sync + Send>),
    /// An error from the Postgres server itself.
    Db(Box<DbError>),
    /// An error initializing the SSL session.
    Ssl(Box<error::Error + Sync + Send>),
    /// An error communicating with the server.
    Io(io::Error),
}

impl fmt::Display for ConnectError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(fmt.write_str(error::Error::description(self)));
        match *self {
            ConnectError::ConnectParams(ref msg) => write!(fmt, ": {}", msg),
            ConnectError::Db(ref err) => write!(fmt, ": {}", err),
            ConnectError::Ssl(ref err) => write!(fmt, ": {}", err),
            ConnectError::Io(ref err) => write!(fmt, ": {}", err),
        }
    }
}

impl error::Error for ConnectError {
    fn description(&self) -> &str {
        match *self {
            ConnectError::ConnectParams(_) => "Invalid connection parameters",
            ConnectError::Db(_) => "Error reported by Postgres",
            ConnectError::Ssl(_) => "Error initiating SSL session",
            ConnectError::Io(_) => "Error communicating with the server",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            ConnectError::ConnectParams(ref err) | ConnectError::Ssl(ref err) => Some(&**err),
            ConnectError::Db(ref err) => Some(&**err),
            ConnectError::Io(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for ConnectError {
    fn from(err: io::Error) -> ConnectError {
        ConnectError::Io(err)
    }
}

impl From<DbError> for ConnectError {
    fn from(err: DbError) -> ConnectError {
        ConnectError::Db(Box::new(err))
    }
}

/// Represents the position of an error in a query.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ErrorPosition {
    /// A position in the original query.
    Normal(u32),
    /// A position in an internally generated query.
    Internal {
        /// The byte position.
        position: u32,
        /// A query generated by the Postgres server.
        query: String,
    },
}

/// An error encountered when communicating with the Postgres server.
#[derive(Debug)]
pub enum Error {
    /// An error reported by the Postgres server.
    Db(Box<DbError>),
    /// An error communicating with the Postgres server.
    Io(io::Error),
    /// An error converting between Postgres and Rust types.
    Conversion(Box<error::Error + Sync + Send>),
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(fmt.write_str(error::Error::description(self)));
        match *self {
            Error::Db(ref err) => write!(fmt, ": {}", err),
            Error::Io(ref err) => write!(fmt, ": {}", err),
            Error::Conversion(ref err) => write!(fmt, ": {}", err),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Db(_) => "Error reported by Postgres",
            Error::Io(_) => "Error communicating with the server",
            Error::Conversion(_) => "Error converting between Postgres and Rust types",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Db(ref err) => Some(&**err),
            Error::Io(ref err) => Some(err),
            Error::Conversion(ref err) => Some(&**err),
        }
    }
}

impl From<DbError> for Error {
    fn from(err: DbError) -> Error {
        Error::Db(Box::new(err))
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<Error> for io::Error {
    fn from(err: Error) -> io::Error {
        io::Error::new(io::ErrorKind::Other, err)
    }
}
<|endoftext|>


<commit_before>pub mod flow;
pub mod connectivity;

// Represents a union of disjoint sets. Each set's elements are arranged in a
// tree, whose root is the set's representative.
pub struct DisjointSets {
    parent: Vec<usize>
}

impl DisjointSets {
    // Initialize disjoint sets containing one element each.
    pub fn new(size: usize) -> DisjointSets {
        DisjointSets { parent: (0..size).collect() }
    }

    // Find the set's representative. Do path compression along the way to make
    // future queries faster.
    pub fn find(&mut self, u: usize) -> usize {
        let pu = self.parent[u];
        if pu != u { self.parent[u] = self.find(pu); }
        self.parent[u]
    }

    // Merge the sets containing u and v into a single set containing their
    // union. Returns true if u and v were previously in different sets.
    pub fn merge(&mut self, u: usize, v: usize) -> bool {
        let (pu, pv) = (self.find(u), self.find(v));
        self.parent[pu] = pv;
        pu != pv
    }
}

// A compact graph representation.
pub struct Graph {
    pub first: Vec<Option<usize>>,
    pub next: Vec<Option<usize>>,
    pub endp: Vec<usize>,
}

impl Graph {
    // Initialize a graph with vmax vertices and no edges. For best efficiency,
    // emax should be a tight upper bound on the number of edges to insert.
    pub fn new(vmax: usize, emax: usize) -> Graph {
        Graph {
            first: vec![None; vmax],
            next: Vec::with_capacity(emax),
            endp: Vec::with_capacity(emax)
        }
    }

    // Utilities to compute the number of vertices and edges.
    pub fn num_v(&self) -> usize { self.first.len() }
    pub fn num_e(&self) -> usize { self.next.len() }

    // Add a directed edge from u to v.
    pub fn add_edge(&mut self, u: usize, v: usize) {
        self.next.push(self.first[u]);
        self.first[u] = Some(self.endp.len());
        self.endp.push(v);
    }

    // An undirected edge is two directed edges. If edges are added only via
    // this funcion, the reverse of any edge e can be found at e^1.
    pub fn add_undirected_edge(&mut self, u: usize, v: usize) {
        self.add_edge(u, v);
        self.add_edge(v, u);
    }

    // If we think of each even-numbered vertex as a variable, and its successor
    // as its negation, then we can build the implication graph corresponding
    // to any 2-CNF formula. Note that u||v == !u -> v == !v -> u.
    pub fn add_two_sat_clause(&mut self, u: usize, v: usize) {
        self.add_edge(u^1, v);
        self.add_edge(v^1, u);
    }

    // Gets vertex u's adjacency list.
    pub fn adj_list<'a>(&'a self, u: usize) -> AdjListIterator<'a> {
        AdjListIterator {
            graph: self,
            next_e: self.first[u]
        }
    }

    // Finds the sequence of edges in an Euler path starting from u, assuming it
    // exists and that the graph is directed. To extend this to undirected
    // graphs, keep track of a visited array to skip the reverse edge.
    pub fn euler_path(&self, u: usize) -> Vec<usize> {
        let mut adj_iters = (0..self.num_v()).map(|u| self.adj_list(u))
                            .collect::<Vec<_>>();
        let mut edges = Vec::with_capacity(self.num_e());
        self.euler_recurse(u, &mut adj_iters, &mut edges);
        edges.reverse();
        edges
    }

    // Helper function used by euler_path. Note that we can't consume the
    // adjacency list in a for loop because recursive calls may need it.
    fn euler_recurse(&self, u: usize, adj: &mut [AdjListIterator], edges: &mut Vec<usize>) {
        while let Some((e, v)) = adj[u].next() {
            self.euler_recurse(v, adj, edges);
            edges.push(e);
        }
    }

    // Kruskal's minimum spanning tree algorithm on an undirected graph.
    pub fn min_spanning_tree(&self, weights: &[i64]) -> Vec<usize> {
        assert_eq!(self.num_e(), 2 * weights.len());
        let mut edges = (0..weights.len()).collect::<Vec<_>>();
        edges.sort_by_key(|&e| weights[e]);

        let mut components = DisjointSets::new(self.num_v());
        edges.into_iter()
            .filter(|&e| components.merge(self.endp[2*e], self.endp[2*e+1]))
            .collect()
    }
}

// An iterator for convenient adjacency list traversal.
pub struct AdjListIterator<'a> {
    graph: &'a Graph,
    next_e: Option<usize>
}

impl<'a> Iterator for AdjListIterator<'a> {
    type Item = (usize, usize);

    // Produces an outgoing edge and vertex.
    fn next(&mut self) -> Option<Self::Item> {
        self.next_e.map( |e| {
            let v = self.graph.endp[e];
            self.next_e = self.graph.next[e];
            (e, v)
        })
    }
}

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

    #[test]
    fn test_euler()
    {
        let mut graph = Graph::new(3, 4);
        graph.add_edge(0, 1);
        graph.add_edge(1, 0);
        graph.add_edge(1, 2);
        graph.add_edge(2, 1);
        assert_eq!(graph.euler_path(0), vec![0, 2, 3, 1]);
    }

    #[test]
    fn test_min_spanning_tree()
    {
        let mut graph = Graph::new(3, 3);
        graph.add_undirected_edge(0, 1);
        graph.add_undirected_edge(1, 2);
        graph.add_undirected_edge(2, 0);
        let weights = [7, 3, 5];
        assert_eq!(graph.min_spanning_tree(&weights), vec![1, 2]);
    }
}
<commit_msg>Test MST's cost<commit_after>pub mod flow;
pub mod connectivity;

// Represents a union of disjoint sets. Each set's elements are arranged in a
// tree, whose root is the set's representative.
pub struct DisjointSets {
    parent: Vec<usize>
}

impl DisjointSets {
    // Initialize disjoint sets containing one element each.
    pub fn new(size: usize) -> DisjointSets {
        DisjointSets { parent: (0..size).collect() }
    }

    // Find the set's representative. Do path compression along the way to make
    // future queries faster.
    pub fn find(&mut self, u: usize) -> usize {
        let pu = self.parent[u];
        if pu != u { self.parent[u] = self.find(pu); }
        self.parent[u]
    }

    // Merge the sets containing u and v into a single set containing their
    // union. Returns true if u and v were previously in different sets.
    pub fn merge(&mut self, u: usize, v: usize) -> bool {
        let (pu, pv) = (self.find(u), self.find(v));
        self.parent[pu] = pv;
        pu != pv
    }
}

// A compact graph representation.
pub struct Graph {
    pub first: Vec<Option<usize>>,
    pub next: Vec<Option<usize>>,
    pub endp: Vec<usize>,
}

impl Graph {
    // Initialize a graph with vmax vertices and no edges. For best efficiency,
    // emax should be a tight upper bound on the number of edges to insert.
    pub fn new(vmax: usize, emax: usize) -> Graph {
        Graph {
            first: vec![None; vmax],
            next: Vec::with_capacity(emax),
            endp: Vec::with_capacity(emax)
        }
    }

    // Utilities to compute the number of vertices and edges.
    pub fn num_v(&self) -> usize { self.first.len() }
    pub fn num_e(&self) -> usize { self.next.len() }

    // Add a directed edge from u to v.
    pub fn add_edge(&mut self, u: usize, v: usize) {
        self.next.push(self.first[u]);
        self.first[u] = Some(self.endp.len());
        self.endp.push(v);
    }

    // An undirected edge is two directed edges. If edges are added only via
    // this funcion, the reverse of any edge e can be found at e^1.
    pub fn add_undirected_edge(&mut self, u: usize, v: usize) {
        self.add_edge(u, v);
        self.add_edge(v, u);
    }

    // If we think of each even-numbered vertex as a variable, and its successor
    // as its negation, then we can build the implication graph corresponding
    // to any 2-CNF formula. Note that u||v == !u -> v == !v -> u.
    pub fn add_two_sat_clause(&mut self, u: usize, v: usize) {
        self.add_edge(u^1, v);
        self.add_edge(v^1, u);
    }

    // Gets vertex u's adjacency list.
    pub fn adj_list<'a>(&'a self, u: usize) -> AdjListIterator<'a> {
        AdjListIterator {
            graph: self,
            next_e: self.first[u]
        }
    }

    // Finds the sequence of edges in an Euler path starting from u, assuming it
    // exists and that the graph is directed. To extend this to undirected
    // graphs, keep track of a visited array to skip the reverse edge.
    pub fn euler_path(&self, u: usize) -> Vec<usize> {
        let mut adj_iters = (0..self.num_v()).map(|u| self.adj_list(u))
                            .collect::<Vec<_>>();
        let mut edges = Vec::with_capacity(self.num_e());
        self.euler_recurse(u, &mut adj_iters, &mut edges);
        edges.reverse();
        edges
    }

    // Helper function used by euler_path. Note that we can't consume the
    // adjacency list in a for loop because recursive calls may need it.
    fn euler_recurse(&self, u: usize, adj: &mut [AdjListIterator], edges: &mut Vec<usize>) {
        while let Some((e, v)) = adj[u].next() {
            self.euler_recurse(v, adj, edges);
            edges.push(e);
        }
    }

    // Kruskal's minimum spanning tree algorithm on an undirected graph.
    pub fn min_spanning_tree(&self, weights: &[i64]) -> Vec<usize> {
        assert_eq!(self.num_e(), 2 * weights.len());
        let mut edges = (0..weights.len()).collect::<Vec<_>>();
        edges.sort_by_key(|&e| weights[e]);

        let mut components = DisjointSets::new(self.num_v());
        edges.into_iter()
            .filter(|&e| components.merge(self.endp[2*e], self.endp[2*e+1]))
            .collect()
    }
}

// An iterator for convenient adjacency list traversal.
pub struct AdjListIterator<'a> {
    graph: &'a Graph,
    next_e: Option<usize>
}

impl<'a> Iterator for AdjListIterator<'a> {
    type Item = (usize, usize);

    // Produces an outgoing edge and vertex.
    fn next(&mut self) -> Option<Self::Item> {
        self.next_e.map( |e| {
            let v = self.graph.endp[e];
            self.next_e = self.graph.next[e];
            (e, v)
        })
    }
}

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

    #[test]
    fn test_euler()
    {
        let mut graph = Graph::new(3, 4);
        graph.add_edge(0, 1);
        graph.add_edge(1, 0);
        graph.add_edge(1, 2);
        graph.add_edge(2, 1);
        assert_eq!(graph.euler_path(0), vec![0, 2, 3, 1]);
    }

    #[test]
    fn test_min_spanning_tree()
    {
        let mut graph = Graph::new(3, 3);
        graph.add_undirected_edge(0, 1);
        graph.add_undirected_edge(1, 2);
        graph.add_undirected_edge(2, 0);
        let weights = [7, 3, 5];
        let mst = graph.min_spanning_tree(&weights);
        let mst_cost = mst.iter().map(|&e| weights[e]).sum::<i64>();
        assert_eq!(mst, vec![1, 2]);
        assert_eq!(mst_cost, 8);
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 lazy-static.rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate std;

use self::std::prelude::v1::*;
use self::std::sync::Once;
pub use self::std::sync::ONCE_INIT;

pub struct Lazy<T: Sync>(pub *const T, pub Once);

impl<T: Sync> Lazy<T> {
    #[inline(always)]
    pub fn get<F>(&'static mut self, f: F) -> &T
        where F: FnOnce() -> T
    {
        unsafe {
            let r = &mut self.0;
            self.1.call_once(|| {
                *r = Box::into_raw(Box::new(f()));
            });

            &*self.0
        }
    }
}

unsafe impl<T: Sync> Sync for Lazy<T> {}

#[macro_export]
#[doc(hidden)]
macro_rules! __lazy_static_create {
    ($NAME:ident, $T:ty) => {
        static mut $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy(0 as *const $T, $crate::lazy::ONCE_INIT);
    }
}
<commit_msg>Use associated constant to make Lazy's fields private.<commit_after>// Copyright 2016 lazy-static.rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate std;

use self::std::prelude::v1::*;
use self::std::sync::Once;
pub use self::std::sync::ONCE_INIT;

pub struct Lazy<T: Sync>(*const T, Once);

impl<T: Sync> Lazy<T> {
    pub const INIT: Self = Lazy(0 as *const T, ONCE_INIT);

    #[inline(always)]
    pub fn get<F>(&'static mut self, f: F) -> &T
    where
        F: FnOnce() -> T,
    {
        unsafe {
            let r = &mut self.0;
            self.1.call_once(|| {
                *r = Box::into_raw(Box::new(f()));
            });

            &*self.0
        }
    }
}

unsafe impl<T: Sync> Sync for Lazy<T> {}

#[macro_export]
#[doc(hidden)]
macro_rules! __lazy_static_create {
    ($NAME:ident, $T:ty) => {
        static mut $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::INIT;
    };
}
<|endoftext|>


<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/writer.rs                                           *
 *                                                        *
 * hprose writer for Rust.                                *
 *                                                        *
 * LastModified: Sep 12, 2016                             *
 * Author: Chen Fei <cf@hprose.com>                       *
 *                                                        *
\**********************************************************/

extern crate test;

use std::i32;
use std::io::Write;
use std::ptr;
use std::string::String;

use super::tags::*;
use super::util::*;
use super::encoder::*;
use super::writer_refer::WriterRefer;

pub struct Writer {
    buf: Vec<u8>,
    refer: Option<WriterRefer>
}

impl Writer {
    pub fn serialize<T: Encoder + ?Sized>(&mut self, v: &T) -> &mut Writer {
        self.write_value(v);
        self
    }

    #[inline]
    pub fn write_value<T: Encoder + ?Sized>(&mut self, v: &T) {
        v.encode(self);
    }

    pub fn write_bool(&mut self, b: bool) {
        self.buf.push(if b { TAG_TRUE } else { TAG_FALSE });
    }

    pub fn write_int(&mut self, i: i64) {
        if i >= 0 && i <= 9 {
            self.buf.push('0' as u8 + i as u8);
            return
        }
        if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
            self.buf.push(TAG_INTEGER);
        } else {
            self.buf.push(TAG_LONG);
        }
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_int_bytes(&mut buf, i));
        self.buf.push(TAG_SEMICOLON);
    }

    pub fn write_uint(&mut self, i: u64) {
        if i <= 9 {
            self.buf.push('0' as u8 + i as u8);
            return
        }
        if i <= i32::MAX as u64 {
            self.buf.push(TAG_INTEGER);
        } else {
            self.buf.push(TAG_LONG);
        }
        write!(self.buf, "{}", i).unwrap();
        self.buf.push(TAG_SEMICOLON);
    }

    pub fn write_float32(&mut self, f: f32) {
        if f.is_nan() {
            self.buf.push(TAG_NAN);
            return
        }
        if f.is_infinite() {
            self.buf.push(TAG_INFINITY);
            self.buf.push(if f.is_sign_negative() { TAG_NEG } else { TAG_POS });
            return
        }
        self.buf.push(TAG_DOUBLE);
        write!(self.buf, "{}", f).unwrap();
        self.buf.push(TAG_SEMICOLON);
    }

    pub fn write_float64(&mut self, f: f64) {
        if f.is_nan() {
            self.buf.push(TAG_NAN);
            return
        }
        if f.is_infinite() {
            self.buf.push(TAG_INFINITY);
            self.buf.push(if f.is_sign_negative() { TAG_NEG } else { TAG_POS });
            return
        }
        self.buf.push(TAG_DOUBLE);
        write!(self.buf, "{}", f).unwrap();
        self.buf.push(TAG_SEMICOLON);
    }

    pub fn write_string(&mut self, s: &str) {
        // todo: add length -1 handler
        let length = utf16_length(s);
        match length {
            0 => self.buf.push(TAG_EMPTY),
            1 => {
                self.buf.push(TAG_UTF8_CHAR);
                write!(self.buf, "{}", s).unwrap()
            },
            _ => {
                self.set_ref(ptr::null::<&str>());
                self.write_string_inner(s, length)
            }
        }
    }

    pub fn write_list<T: Encoder>(&mut self, lst: &Vec<T>) {
        if self.write_ref(lst) {
            return
        }
        self.set_ref(lst);
        let count = lst.len();
        if count == 0 {
            self.write_empty_list();
            return
        }
        self.write_list_header(count as i64);
        for v in lst {
            self.serialize(v);
        }
        self.write_list_footer();
    }

    pub fn write_slice<T: Encoder>(&mut self, slice: &[T]) {
        self.set_ref(ptr::null::<&[T]>());
        let count = slice.len();
        if count == 0 {
            self.write_empty_list();
            return
        }
        self.write_list_header(count as i64);
        for v in slice {
            self.serialize(v);
        }
        self.write_list_footer();
    }

    // private functions

    #[inline]
    fn write_ref<T>(&mut self, p: *const T) -> bool {
        let buf = &mut self.buf;
        self.refer.as_mut().map_or(true, |r| r.write(buf, p))
    }

    #[inline]
    fn set_ref<T>(&mut self, p: *const T) {
        self.refer.as_mut().map(|r| r.set(p));
    }

    fn write_string_inner(&mut self, s: &str, length: i64) {
        self.buf.push(TAG_STRING);
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_int_bytes(&mut buf, length));
        self.buf.push(TAG_QUOTE);
        self.buf.extend_from_slice(s.as_bytes());
        self.buf.push(TAG_QUOTE);
    }

    fn write_list_header(&mut self, count: i64) {
        self.buf.push(TAG_LIST);
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_int_bytes(&mut buf, count));
        self.buf.push(TAG_OPENBRACE);
    }

    #[inline]
    fn write_list_footer(&mut self) {
        self.buf.push(TAG_CLOSEBRACE);
    }

    fn write_empty_list(&mut self) {
        self.buf.push(TAG_LIST);
        self.buf.push(TAG_OPENBRACE);
        self.buf.push(TAG_CLOSEBRACE);
    }

    pub fn clear(&mut self) {
        self.buf.clear();
    }

    pub fn bytes(&mut self) -> Vec<u8> {
        self.buf.clone()
    }

    pub fn string(&mut self) -> String {
        String::from_utf8(self.buf.clone()).unwrap()
    }

    #[inline]
    pub fn new(simple: bool) -> Writer {
        Writer {
            buf: Vec::with_capacity(1024),
            refer: if simple { None } else { Some(WriterRefer::new()) }
        }
    }
}

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

    use std::{f32, f64};

    #[test]
    fn test_serialize_bool() {
        let mut w = Writer::new(true);
        w.serialize(&true);
        assert_eq!(w.string(), "t");
        w.clear();
        w.serialize(&false);
        assert_eq!(w.string(), "f");
    }

    #[bench]
    fn benchmark_serialize_bool(b: &mut Bencher) {
        let mut w = Writer::new(true);
        b.iter(|| {
            w.serialize(&true);
        });
    }

    #[test]
    fn test_serialize_int() {
        let mut w = Writer::new(true);
        w.serialize(&8);
        assert_eq!(w.string(), "8");
        w.clear();
        w.serialize(&88);
        assert_eq!(w.string(), "i88;");
    }

    #[bench]
    fn benchmark_serialize_int(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let mut i: i64 = 1;
        b.iter(|| {
            w.serialize(&i);
            i += 1;
        });
    }

    #[test]
    fn test_serialize_float32() {
        let test_cases = [
            (f32::NAN, "N"),
            (f32::INFINITY, "I+"),
            (f32::NEG_INFINITY, "I-"),
            (f32::consts::PI, "d3.1415927;")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(&test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_float32(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let mut i: f32 = 1.0;
        b.iter(|| {
            w.serialize(&i);
            i += 1.0;
        });
    }

    #[test]
    fn test_serialize_float64() {
        let test_cases = [
            (f64::NAN, "N"),
            (f64::INFINITY, "I+"),
            (f64::NEG_INFINITY, "I-"),
            (f64::consts::PI, "d3.141592653589793;")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(&test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_float64(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let mut i: f64 = 1.0;
        b.iter(|| {
            w.serialize(&i);
            i += 1.0;
        });
    }

    #[test]
    fn test_serialize_string() {
        let test_cases = [
            ("", "e"),
            ("π", "uπ"),
            ("你", "u你"),
            ("你好", "s2\"你好\""),
            ("你好啊,hello!", "s10\"你好啊,hello!\""),
            ("🇨🇳", "s4\"🇨🇳\"")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_string(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let s = "你好,hello!";
        b.iter(|| {
            w.serialize(s);
        });
    }
}
<commit_msg>Added int slice benchmark.<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/writer.rs                                           *
 *                                                        *
 * hprose writer for Rust.                                *
 *                                                        *
 * LastModified: Sep 12, 2016                             *
 * Author: Chen Fei <cf@hprose.com>                       *
 *                                                        *
\**********************************************************/

extern crate test;

use std::i32;
use std::io::Write;
use std::ptr;
use std::string::String;

use super::tags::*;
use super::util::*;
use super::encoder::*;
use super::writer_refer::WriterRefer;

pub struct Writer {
    buf: Vec<u8>,
    refer: Option<WriterRefer>
}

impl Writer {
    pub fn serialize<T: Encoder + ?Sized>(&mut self, v: &T) -> &mut Writer {
        self.write_value(v);
        self
    }

    #[inline]
    pub fn write_value<T: Encoder + ?Sized>(&mut self, v: &T) {
        v.encode(self);
    }

    pub fn write_bool(&mut self, b: bool) {
        self.buf.push(if b { TAG_TRUE } else { TAG_FALSE });
    }

    pub fn write_int(&mut self, i: i64) {
        if i >= 0 && i <= 9 {
            self.buf.push('0' as u8 + i as u8);
            return
        }
        if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
            self.buf.push(TAG_INTEGER);
        } else {
            self.buf.push(TAG_LONG);
        }
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_int_bytes(&mut buf, i));
        self.buf.push(TAG_SEMICOLON);
    }

    pub fn write_uint(&mut self, i: u64) {
        if i <= 9 {
            self.buf.push('0' as u8 + i as u8);
            return
        }
        if i <= i32::MAX as u64 {
            self.buf.push(TAG_INTEGER);
        } else {
            self.buf.push(TAG_LONG);
        }
        write!(self.buf, "{}", i).unwrap();
        self.buf.push(TAG_SEMICOLON);
    }

    pub fn write_float32(&mut self, f: f32) {
        if f.is_nan() {
            self.buf.push(TAG_NAN);
            return
        }
        if f.is_infinite() {
            self.buf.push(TAG_INFINITY);
            self.buf.push(if f.is_sign_negative() { TAG_NEG } else { TAG_POS });
            return
        }
        self.buf.push(TAG_DOUBLE);
        write!(self.buf, "{}", f).unwrap();
        self.buf.push(TAG_SEMICOLON);
    }

    pub fn write_float64(&mut self, f: f64) {
        if f.is_nan() {
            self.buf.push(TAG_NAN);
            return
        }
        if f.is_infinite() {
            self.buf.push(TAG_INFINITY);
            self.buf.push(if f.is_sign_negative() { TAG_NEG } else { TAG_POS });
            return
        }
        self.buf.push(TAG_DOUBLE);
        write!(self.buf, "{}", f).unwrap();
        self.buf.push(TAG_SEMICOLON);
    }

    pub fn write_string(&mut self, s: &str) {
        // todo: add length -1 handler
        let length = utf16_length(s);
        match length {
            0 => self.buf.push(TAG_EMPTY),
            1 => {
                self.buf.push(TAG_UTF8_CHAR);
                write!(self.buf, "{}", s).unwrap()
            },
            _ => {
                self.set_ref(ptr::null::<&str>());
                self.write_string_inner(s, length)
            }
        }
    }

    pub fn write_list<T: Encoder>(&mut self, lst: &Vec<T>) {
        if self.write_ref(lst) {
            return
        }
        self.set_ref(lst);
        let count = lst.len();
        if count == 0 {
            self.write_empty_list();
            return
        }
        self.write_list_header(count as i64);
        for v in lst {
            self.serialize(v);
        }
        self.write_list_footer();
    }

    pub fn write_slice<T: Encoder>(&mut self, slice: &[T]) {
        self.set_ref(ptr::null::<&[T]>());
        let count = slice.len();
        if count == 0 {
            self.write_empty_list();
            return
        }
        self.write_list_header(count as i64);
        for v in slice {
            self.serialize(v);
        }
        self.write_list_footer();
    }

    // private functions

    #[inline]
    fn write_ref<T>(&mut self, p: *const T) -> bool {
        let buf = &mut self.buf;
        self.refer.as_mut().map_or(true, |r| r.write(buf, p))
    }

    #[inline]
    fn set_ref<T>(&mut self, p: *const T) {
        self.refer.as_mut().map(|r| r.set(p));
    }

    fn write_string_inner(&mut self, s: &str, length: i64) {
        self.buf.push(TAG_STRING);
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_int_bytes(&mut buf, length));
        self.buf.push(TAG_QUOTE);
        self.buf.extend_from_slice(s.as_bytes());
        self.buf.push(TAG_QUOTE);
    }

    fn write_list_header(&mut self, count: i64) {
        self.buf.push(TAG_LIST);
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_int_bytes(&mut buf, count));
        self.buf.push(TAG_OPENBRACE);
    }

    #[inline]
    fn write_list_footer(&mut self) {
        self.buf.push(TAG_CLOSEBRACE);
    }

    fn write_empty_list(&mut self) {
        self.buf.push(TAG_LIST);
        self.buf.push(TAG_OPENBRACE);
        self.buf.push(TAG_CLOSEBRACE);
    }

    pub fn clear(&mut self) {
        self.buf.clear();
    }

    pub fn bytes(&mut self) -> Vec<u8> {
        self.buf.clone()
    }

    pub fn string(&mut self) -> String {
        String::from_utf8(self.buf.clone()).unwrap()
    }

    #[inline]
    pub fn new(simple: bool) -> Writer {
        Writer {
            buf: Vec::with_capacity(1024),
            refer: if simple { None } else { Some(WriterRefer::new()) }
        }
    }
}

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

    use std::{f32, f64};

    #[test]
    fn test_serialize_bool() {
        let mut w = Writer::new(true);
        w.serialize(&true);
        assert_eq!(w.string(), "t");
        w.clear();
        w.serialize(&false);
        assert_eq!(w.string(), "f");
    }

    #[bench]
    fn benchmark_serialize_bool(b: &mut Bencher) {
        let mut w = Writer::new(true);
        b.iter(|| {
            w.serialize(&true);
        });
    }

    #[test]
    fn test_serialize_int() {
        let mut w = Writer::new(true);
        w.serialize(&8);
        assert_eq!(w.string(), "8");
        w.clear();
        w.serialize(&88);
        assert_eq!(w.string(), "i88;");
    }

    #[bench]
    fn benchmark_serialize_int(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let mut i: i64 = 1;
        b.iter(|| {
            w.serialize(&i);
            i += 1;
        });
    }

    #[test]
    fn test_serialize_float32() {
        let test_cases = [
            (f32::NAN, "N"),
            (f32::INFINITY, "I+"),
            (f32::NEG_INFINITY, "I-"),
            (f32::consts::PI, "d3.1415927;")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(&test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_float32(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let mut i: f32 = 1.0;
        b.iter(|| {
            w.serialize(&i);
            i += 1.0;
        });
    }

    #[test]
    fn test_serialize_float64() {
        let test_cases = [
            (f64::NAN, "N"),
            (f64::INFINITY, "I+"),
            (f64::NEG_INFINITY, "I-"),
            (f64::consts::PI, "d3.141592653589793;")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(&test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_float64(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let mut i: f64 = 1.0;
        b.iter(|| {
            w.serialize(&i);
            i += 1.0;
        });
    }

    #[test]
    fn test_serialize_string() {
        let test_cases = [
            ("", "e"),
            ("π", "uπ"),
            ("你", "u你"),
            ("你好", "s2\"你好\""),
            ("你好啊,hello!", "s10\"你好啊,hello!\""),
            ("🇨🇳", "s4\"🇨🇳\"")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_string(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let s = "你好,hello!";
        b.iter(|| {
            w.serialize(s);
        });
    }

    #[bench]
    fn benchmark_serialize_int_slice(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let array = [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 1, 2, 3, 4, 0, 1, 2, 3, 4];
        let slice = &array[..];
        b.iter(|| {
            w.serialize(slice);
        });
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

// SVG 1.1 (Second Edition)
// https://www.w3.org/TR/SVG/
<% data.new_style_struct("InheritedSVG",
                         inherited=True,
                         gecko_name="SVG") %>

// Section 10 - Text

${helpers.single_keyword("text-anchor",
                         "start middle end",
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG/text.html#TextAnchorProperty")}

// Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword("color-interpolation",
                         "srgb auto linearrgb",
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty")}

${helpers.single_keyword("color-interpolation-filters", "linearrgb auto srgb",
                         products="gecko",
                         gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty")}

${helpers.predefined_type(
    "fill", "SVGPaint",
    "::values::computed::SVGPaint::black()",
    products="gecko",
    animation_value_type="IntermediateSVGPaint",
    boxed=True,
    spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint")}

${helpers.predefined_type("fill-opacity", "Opacity", "1.0",
                          products="gecko", animation_value_type="none",
                          spec="https://www.w3.org/TR/SVG11/painting.html#FillOpacityProperty")}

${helpers.single_keyword("fill-rule", "nonzero evenodd",
                         gecko_enum_prefix="StyleFillRule",
                         gecko_inexhaustive=True,
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#FillRuleProperty")}

${helpers.single_keyword("shape-rendering",
                         "auto optimizespeed crispedges geometricprecision",
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty")}

${helpers.predefined_type(
    "stroke", "SVGPaint",
    "Default::default()",
    products="gecko",
    animation_value_type="IntermediateSVGPaint",
    boxed=True,
    spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint")}

${helpers.predefined_type(
    "stroke-width", "LengthOrPercentageOrNumber",
    "Either::First(1.0)",
    "parse_non_negative",
    products="gecko",
    animation_value_type="ComputedValue",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth")}

${helpers.single_keyword("stroke-linecap", "butt round square",
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty")}

${helpers.single_keyword("stroke-linejoin", "miter round bevel",
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty")}

${helpers.predefined_type("stroke-miterlimit", "Number", "4.0",
                          "parse_at_least_one", products="gecko",
                          animation_value_type="ComputedValue",
                          spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty")}

${helpers.predefined_type("stroke-opacity", "Opacity", "1.0",
                          products="gecko", animation_value_type="ComputedValue",
                          spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty")}

${helpers.predefined_type("stroke-dasharray",
                          "LengthOrPercentageOrNumber",
                          "Either::First(0.0)",
                          "parse_non_negative",
                          vector="True",
                          delegate_animate="True",
                          allow_empty="True",
                          products="gecko",
                          animation_value_type="ComputedValue",
                          space_separated_allowed="True",
                          spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}

${helpers.predefined_type(
    "stroke-dashoffset", "LengthOrPercentageOrNumber",
    "Either::First(0.0)",
    products="gecko",
    animation_value_type="ComputedValue",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}

// Section 14 - Clipping, Masking and Compositing
${helpers.single_keyword("clip-rule", "nonzero evenodd",
                         products="gecko",
                         gecko_enum_prefix="StyleFillRule",
                         gecko_inexhaustive=True,
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/masking.html#ClipRuleProperty")}

${helpers.predefined_type("marker-start", "UrlOrNone", "Either::Second(None_)",
                          products="gecko",
                          boxed="True" if product == "gecko" else "False",
                          animation_value_type="none",
                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}

${helpers.predefined_type("marker-mid", "UrlOrNone", "Either::Second(None_)",
                          products="gecko",
                          boxed="True" if product == "gecko" else "False",
                          animation_value_type="none",
                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}

${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
                          products="gecko",
                          boxed="True" if product == "gecko" else "False",
                          animation_value_type="none",
                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}

<%helpers:longhand name="paint-order"
                   animation_value_type="none"
                   products="gecko"
                   spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder">

    use values::computed::ComputedValueAsSpecified;
    use std::fmt;
    use style_traits::ToCss;

    pub const NORMAL: u8 = 0;
    pub const FILL: u8 = 1;
    pub const STROKE: u8 = 2;
    pub const MARKERS: u8 = 3;

    // number of bits for each component
    pub const SHIFT: u8 = 2;
    // mask with above bits set
    pub const MASK: u8 = 0b11;
    // number of non-normal keyword values
    pub const COUNT: u8 = 3;
    // all keywords
    pub const ALL: [u8; 3] = [FILL, STROKE, MARKERS];

    /// Represented as a six-bit field, of 3 two-bit pairs
    ///
    /// Each pair can be set to FILL, STROKE, or MARKERS
    /// Lowest significant bit pairs are highest priority.
    ///  `normal` is the empty bitfield. The three pairs are
    /// never zero in any case other than `normal`.
    ///
    /// Higher priority values, i.e. the values specified first,
    /// will be painted first (and may be covered by paintings of lower priority)
    #[derive(PartialEq, Clone, Copy, Debug)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    pub struct SpecifiedValue(pub u8);

    pub mod computed_value {
        pub use super::SpecifiedValue as T;
    }

    pub fn get_initial_value() -> SpecifiedValue {
      SpecifiedValue(NORMAL)
    }

    impl SpecifiedValue {
        pub fn bits_at(&self, pos: u8) -> u8 {
            (self.0 >> pos * SHIFT) & MASK
        }
    }

    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
        if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) {
            Ok(SpecifiedValue(0))
        } else {
            let mut value = 0;
            // bitfield representing what we've seen so far
            // bit 1 is fill, bit 2 is stroke, bit 3 is markers
            let mut seen = 0;
            let mut pos = 0;

            loop {

                let result = input.try(|i| {
                    match_ignore_ascii_case! { &i.expect_ident()?,
                        "fill" => Ok(FILL),
                        "stroke" => Ok(STROKE),
                        "markers" => Ok(MARKERS),
                        _ => Err(())
                    }
                });

                match result {
                    Ok(val) => {
                        if (seen & (1 << val)) != 0 {
                            // don't parse the same ident twice
                            return Err(())
                        } else {
                            value |= val << (pos * SHIFT);
                            seen |= 1 << val;
                            pos += 1;
                        }
                    }
                    Err(()) => break,
                }
            }

            if value == 0 {
                // couldn't find any keyword
                Err(())
            } else {
                // fill in rest
                for i in pos..COUNT {
                    for paint in &ALL {
                        // if not seen, set bit at position, mark as seen
                        if (seen & (1 << paint)) == 0 {
                            seen |= 1 << paint;
                            value |= paint << (i * SHIFT);
                            break;
                        }
                    }
                }

                Ok(SpecifiedValue(value))
            }
        }
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if self.0 == 0 {
                return dest.write_str("normal")
            }

            for pos in 0..COUNT {
                if pos != 0 {
                    dest.write_str(" ")?
                }
                match self.bits_at(pos) {
                    FILL => dest.write_str("fill")?,
                    STROKE => dest.write_str("stroke")?,
                    MARKERS => dest.write_str("markers")?,
                    _ => unreachable!(),
                }
            }
            Ok(())
        }
    }

    no_viewport_percentage!(SpecifiedValue);

    impl ComputedValueAsSpecified for SpecifiedValue { }
</%helpers:longhand>
<%helpers:vector_longhand name="-moz-context-properties"
                   animation_value_type="none"
                   products="gecko"
                   spec="Nonstandard (Internal-only)"
                   internal="True"
                   allow_empty="True">
    use values::CustomIdent;
    use values::computed::ComputedValueAsSpecified;

    no_viewport_percentage!(SpecifiedValue);

    impl ComputedValueAsSpecified for SpecifiedValue { }

    pub type SpecifiedValue = CustomIdent;

    pub mod computed_value {
        pub type T = super::SpecifiedValue;
    }

    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        let i = input.expect_ident()?;
        CustomIdent::from_ident(i, &["all", "none", "auto"])
    }
</%helpers:vector_longhand>
<commit_msg>Bug 1369624 - stylo: make fill-opacity animatable.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

// SVG 1.1 (Second Edition)
// https://www.w3.org/TR/SVG/
<% data.new_style_struct("InheritedSVG",
                         inherited=True,
                         gecko_name="SVG") %>

// Section 10 - Text

${helpers.single_keyword("text-anchor",
                         "start middle end",
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG/text.html#TextAnchorProperty")}

// Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword("color-interpolation",
                         "srgb auto linearrgb",
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty")}

${helpers.single_keyword("color-interpolation-filters", "linearrgb auto srgb",
                         products="gecko",
                         gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty")}

${helpers.predefined_type(
    "fill", "SVGPaint",
    "::values::computed::SVGPaint::black()",
    products="gecko",
    animation_value_type="IntermediateSVGPaint",
    boxed=True,
    spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint")}

${helpers.predefined_type("fill-opacity", "Opacity", "1.0",
                          products="gecko", animation_value_type="ComputedValue",
                          spec="https://www.w3.org/TR/SVG11/painting.html#FillOpacityProperty")}

${helpers.single_keyword("fill-rule", "nonzero evenodd",
                         gecko_enum_prefix="StyleFillRule",
                         gecko_inexhaustive=True,
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#FillRuleProperty")}

${helpers.single_keyword("shape-rendering",
                         "auto optimizespeed crispedges geometricprecision",
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty")}

${helpers.predefined_type(
    "stroke", "SVGPaint",
    "Default::default()",
    products="gecko",
    animation_value_type="IntermediateSVGPaint",
    boxed=True,
    spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint")}

${helpers.predefined_type(
    "stroke-width", "LengthOrPercentageOrNumber",
    "Either::First(1.0)",
    "parse_non_negative",
    products="gecko",
    animation_value_type="ComputedValue",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth")}

${helpers.single_keyword("stroke-linecap", "butt round square",
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty")}

${helpers.single_keyword("stroke-linejoin", "miter round bevel",
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty")}

${helpers.predefined_type("stroke-miterlimit", "Number", "4.0",
                          "parse_at_least_one", products="gecko",
                          animation_value_type="ComputedValue",
                          spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty")}

${helpers.predefined_type("stroke-opacity", "Opacity", "1.0",
                          products="gecko", animation_value_type="ComputedValue",
                          spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty")}

${helpers.predefined_type("stroke-dasharray",
                          "LengthOrPercentageOrNumber",
                          "Either::First(0.0)",
                          "parse_non_negative",
                          vector="True",
                          delegate_animate="True",
                          allow_empty="True",
                          products="gecko",
                          animation_value_type="ComputedValue",
                          space_separated_allowed="True",
                          spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}

${helpers.predefined_type(
    "stroke-dashoffset", "LengthOrPercentageOrNumber",
    "Either::First(0.0)",
    products="gecko",
    animation_value_type="ComputedValue",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}

// Section 14 - Clipping, Masking and Compositing
${helpers.single_keyword("clip-rule", "nonzero evenodd",
                         products="gecko",
                         gecko_enum_prefix="StyleFillRule",
                         gecko_inexhaustive=True,
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/masking.html#ClipRuleProperty")}

${helpers.predefined_type("marker-start", "UrlOrNone", "Either::Second(None_)",
                          products="gecko",
                          boxed="True" if product == "gecko" else "False",
                          animation_value_type="none",
                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}

${helpers.predefined_type("marker-mid", "UrlOrNone", "Either::Second(None_)",
                          products="gecko",
                          boxed="True" if product == "gecko" else "False",
                          animation_value_type="none",
                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}

${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
                          products="gecko",
                          boxed="True" if product == "gecko" else "False",
                          animation_value_type="none",
                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}

<%helpers:longhand name="paint-order"
                   animation_value_type="none"
                   products="gecko"
                   spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder">

    use values::computed::ComputedValueAsSpecified;
    use std::fmt;
    use style_traits::ToCss;

    pub const NORMAL: u8 = 0;
    pub const FILL: u8 = 1;
    pub const STROKE: u8 = 2;
    pub const MARKERS: u8 = 3;

    // number of bits for each component
    pub const SHIFT: u8 = 2;
    // mask with above bits set
    pub const MASK: u8 = 0b11;
    // number of non-normal keyword values
    pub const COUNT: u8 = 3;
    // all keywords
    pub const ALL: [u8; 3] = [FILL, STROKE, MARKERS];

    /// Represented as a six-bit field, of 3 two-bit pairs
    ///
    /// Each pair can be set to FILL, STROKE, or MARKERS
    /// Lowest significant bit pairs are highest priority.
    ///  `normal` is the empty bitfield. The three pairs are
    /// never zero in any case other than `normal`.
    ///
    /// Higher priority values, i.e. the values specified first,
    /// will be painted first (and may be covered by paintings of lower priority)
    #[derive(PartialEq, Clone, Copy, Debug)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    pub struct SpecifiedValue(pub u8);

    pub mod computed_value {
        pub use super::SpecifiedValue as T;
    }

    pub fn get_initial_value() -> SpecifiedValue {
      SpecifiedValue(NORMAL)
    }

    impl SpecifiedValue {
        pub fn bits_at(&self, pos: u8) -> u8 {
            (self.0 >> pos * SHIFT) & MASK
        }
    }

    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
        if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) {
            Ok(SpecifiedValue(0))
        } else {
            let mut value = 0;
            // bitfield representing what we've seen so far
            // bit 1 is fill, bit 2 is stroke, bit 3 is markers
            let mut seen = 0;
            let mut pos = 0;

            loop {

                let result = input.try(|i| {
                    match_ignore_ascii_case! { &i.expect_ident()?,
                        "fill" => Ok(FILL),
                        "stroke" => Ok(STROKE),
                        "markers" => Ok(MARKERS),
                        _ => Err(())
                    }
                });

                match result {
                    Ok(val) => {
                        if (seen & (1 << val)) != 0 {
                            // don't parse the same ident twice
                            return Err(())
                        } else {
                            value |= val << (pos * SHIFT);
                            seen |= 1 << val;
                            pos += 1;
                        }
                    }
                    Err(()) => break,
                }
            }

            if value == 0 {
                // couldn't find any keyword
                Err(())
            } else {
                // fill in rest
                for i in pos..COUNT {
                    for paint in &ALL {
                        // if not seen, set bit at position, mark as seen
                        if (seen & (1 << paint)) == 0 {
                            seen |= 1 << paint;
                            value |= paint << (i * SHIFT);
                            break;
                        }
                    }
                }

                Ok(SpecifiedValue(value))
            }
        }
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if self.0 == 0 {
                return dest.write_str("normal")
            }

            for pos in 0..COUNT {
                if pos != 0 {
                    dest.write_str(" ")?
                }
                match self.bits_at(pos) {
                    FILL => dest.write_str("fill")?,
                    STROKE => dest.write_str("stroke")?,
                    MARKERS => dest.write_str("markers")?,
                    _ => unreachable!(),
                }
            }
            Ok(())
        }
    }

    no_viewport_percentage!(SpecifiedValue);

    impl ComputedValueAsSpecified for SpecifiedValue { }
</%helpers:longhand>
<%helpers:vector_longhand name="-moz-context-properties"
                   animation_value_type="none"
                   products="gecko"
                   spec="Nonstandard (Internal-only)"
                   internal="True"
                   allow_empty="True">
    use values::CustomIdent;
    use values::computed::ComputedValueAsSpecified;

    no_viewport_percentage!(SpecifiedValue);

    impl ComputedValueAsSpecified for SpecifiedValue { }

    pub type SpecifiedValue = CustomIdent;

    pub mod computed_value {
        pub type T = super::SpecifiedValue;
    }

    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        let i = input.expect_ident()?;
        CustomIdent::from_ident(i, &["all", "none", "auto"])
    }
</%helpers:vector_longhand>
<|endoftext|>