<commit_before>use std::task::TaskBuilder;

use uuid::Uuid;
use addr::Addr;
use result::{GossipResult, GossipError, NotListening};

/// A peer describes a member within the cluster/network that
/// is not the current one.
#[deriving(Show, PartialEq)]
pub struct Peer {
    id: Uuid,
    addr: Addr
}

#[deriving(Show, PartialEq)]
pub enum NodeTaskMsg {
    Bind,
    Shutdown
}

pub struct Node {
    id: Uuid,
    addr: Option<Addr>,
    members: Vec<Peer>,
    listening: bool,
    sender: Option<Sender<NodeTaskMsg>>
}

impl Node {
    /// Usage:
    ///
    /// ```rust
    /// use gossip::Node;
    ///
    /// let node = Node::new();
    /// ```
    pub fn new() -> Node {
        Node {
            id: Uuid::new_v4(),
            addr: None,
            members: Vec::new(),
            listening: false,
            sender: None
        }
    }

    /// Usage:
    ///
    /// ```rust
    /// use gossip::Node;
    ///
    /// let node = Node::new();
    /// node.listening();
    /// ```
    pub fn listening(&self) -> bool {
        self.listening
    }

    /// Usage:
    ///
    /// ```rust
    /// use gossip::Node;
    /// use std::io::timer::sleep;
    /// use std::time::duration::Duration;
    ///
    /// let mut node = Node::new();
    ///
    /// // Bind the node to the specified address:
    /// node.bind("127.0.0.1", 5899);
    ///
    /// // Wait for 10 milliseconds then shutdown.
    /// sleep(Duration::milliseconds(10));
    ///
    /// // Kill the server:
    /// match node.shutdown() {
    ///     Ok(_) => println!("Node has successfully been terminated"),
    ///     Err(err) => fail!("Node failed to shutdown")
    /// }
    /// ```
    pub fn bind(&mut self, ip: &str, port: u16) {
        self.listening = true;
        self.addr = Some(Addr::new(ip, port));

        let (tx, rx) = channel();

        TaskBuilder::new().named("NodeBackgroundProcess").spawn(proc() {
            let (sender, receiver) = channel::<NodeTaskMsg>();

            tx.send(sender);

            for m in receiver.iter() {
                match m {
                    Shutdown => break,
                    _ => {}
                }
            }
        });

        self.sender = Some(rx.recv());
    }

    /// Shutdown the current node.
    pub fn shutdown(&mut self) -> GossipResult<()> {
        self.listening = false;

        match self.sender {
            Some(ref tx) => tx.send(Shutdown),
            None => return Err(GossipError::new("The node is not running. Shutdown operation
                                                failed!", NotListening))
        }

        Ok(())
    }
}

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

    #[test]
    fn should_create_node_without_listening() {
        let node = Node::new();
        assert_eq!(node.listening(), false);
    }

    #[test]
    fn empty_member_set() {
        let node = Node::new();
        assert_eq!(node.members.len(), 0);
    }

    #[test]
    fn bind_listening() {
        let mut node = Node::new();
        node.bind("127.0.0.1", 6888);
        assert_eq!(node.listening(), true);
    }
}
<commit_msg>Abstracted the node task into a proper NodeTask struct<commit_after>use std::task::TaskBuilder;

use uuid::Uuid;
use addr::Addr;
use result::{GossipResult, GossipError, NotListening};
use broadcast::Broadcast;

/// A peer describes a member within the cluster/network that
/// is not the current one.
#[deriving(Show, PartialEq)]
pub struct Peer {
    id: Uuid,
    addr: Addr
}

#[deriving(Show, PartialEq)]
pub enum NodeTaskMsg {
    Bind,
    Shutdown
}

#[deriving(Show, PartialEq)]
pub enum NodeMsg {
    BroadcastMsg(Broadcast)
}

pub struct NodeTask {
    receiver: Receiver<NodeTaskMsg>,
    senders: Vec<Sender<NodeMsg>>
}

impl NodeTask {
    pub fn new(tx: Sender<NodeMsg>, rx: Receiver<NodeTaskMsg>) -> NodeTask {
        NodeTask {
            receiver: rx,
            senders: vec![tx]
        }
    }

    pub fn run(&mut self) {
        for message in self.receiver.iter() {
            match message {
                Shutdown => break,
                _ => {}
            }
        }
    }
}

pub struct Node {
    id: Uuid,
    addr: Option<Addr>,
    members: Vec<Peer>,
    listening: bool,
    sender: Option<Sender<NodeTaskMsg>>,
    receiver: Option<Receiver<NodeMsg>>
}

impl Node {
    /// Usage:
    ///
    /// ```rust
    /// use gossip::Node;
    ///
    /// let node = Node::new();
    /// ```
    pub fn new() -> Node {
        Node {
            id: Uuid::new_v4(),
            addr: None,
            members: Vec::new(),
            listening: false,
            sender: None,
            receiver: None
        }
    }

    /// Usage:
    ///
    /// ```rust
    /// use gossip::Node;
    ///
    /// let node = Node::new();
    /// node.listening();
    /// ```
    pub fn listening(&self) -> bool {
        self.listening
    }

    /// Usage:
    ///
    /// ```rust
    /// use gossip::Node;
    ///
    /// let mut node = Node::new();
    ///
    /// // Bind the node to the specified address:
    /// node.bind("127.0.0.1", 5899);
    ///
    /// // Kill the server:
    /// match node.shutdown() {
    ///     Ok(_) => println!("Node has successfully been terminated"),
    ///     Err(err) => fail!("Node failed to shutdown")
    /// }
    /// ```
    pub fn bind(&mut self, ip: &str, port: u16) {
        self.listening = true;
        self.addr = Some(Addr::new(ip, port));

        let (tx, rx) = channel();
        let (local_tx, local_rx) = channel();
        let tx_task = local_tx.clone();

        TaskBuilder::new().named("NodeTask").spawn(proc() {
            let (sender, receiver) = channel::<NodeTaskMsg>();
            tx.send(sender);

            NodeTask::new(tx_task, receiver).run();
        });

        self.sender = Some(rx.recv());
        self.receiver = Some(local_rx);
    }

    /// Shutdown the current node.
    pub fn shutdown(&mut self) -> GossipResult<()> {
        self.listening = false;

        match self.sender {
            Some(ref tx) => tx.send(Shutdown),
            None => return Err(GossipError::new("The node is not running. Shutdown operation
                                                failed!", NotListening))
        }

        Ok(())
    }
}

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

    #[test]
    fn should_create_node_without_listening() {
        let node = Node::new();
        assert_eq!(node.listening(), false);
    }

    #[test]
    fn empty_member_set() {
        let node = Node::new();
        assert_eq!(node.members.len(), 0);
    }

    #[test]
    fn bind_listening() {
        let mut node = Node::new();
        node.bind("127.0.0.1", 6888);
        assert_eq!(node.listening(), true);
        match node.shutdown() {
            Ok(_) => {},
            Err(err) => fail!("Failed to shutdown")
        }
    }
}
<|endoftext|>


<commit_before>use controller::Controller;
use cmd_class::basic::Basic;
use std::rc::Rc;
use std::cell::RefCell;
use num::FromPrimitive;
use msg::{Message, Type, Function};

// The private representation of a node
struct _Node {
    id: u8,
    controller: Controller,
    generic_type: GenericType,
    class_basic: Option<Basic>
}

// reference type for the node
type NodeRef = Rc<RefCell<_Node>>;

// The public representation of a node, with some syntactic sugar.
#[derive(Clone)]
pub struct Node(NodeRef);

// The actual node implementation
impl Node {
    /// Creates a new node with no edges.
    pub fn new(contr: Controller, id: u8) -> Node {
        let node = Node(Rc::new(RefCell::new(_Node {
            id: id,
            controller: contr,
            generic_type: GenericType::Unknown,
            class_basic: None
        })));

        node.discover_type();
        node.discover_classes();

        node
    }

    /// Sets the available type for this node
    pub fn discover_type(&self) {
        let mut this = &mut self.0.borrow_mut();

        // create a new message
        let msg = Message::new(Type::Request, Function::GetNodeProtocolInfo, vec!(this.id));

        // send the message to the ZWave driver
        let msg = unwrap_or_return!(this.controller.get_driver().write_and_read(msg).ok(), ());

        //check if the answer has the right length && is no error
        if msg.data.len() != 6 {
            this.generic_type = GenericType::Unknown;
            return;
        }

        // extract the delivered type
        this.generic_type = GenericType::from_u8(msg.data[4]).unwrap_or(GenericType::Unknown);
    }

    /// Sets the available function classes for this node
    pub fn discover_classes(&self) {
        let mut this = &mut self.0.borrow_mut();

        // todo get the information from the device

        // basic is always available
        this.class_basic = Some(Basic::new(self.clone()));
    }

    /// returns the controller
    pub fn get_controller(&self) -> Controller {
        self.0.borrow().controller.clone()
    }

    /// returns the basic command class to interact with
    pub fn get_basic(&self) -> Option<Basic> {
        self.0.borrow_mut().class_basic.clone()
    }

    /// returns the id of the node in the zwave network
    pub fn get_id(&self) -> u8 {
        self.0.borrow().id.clone()
    }

    // returns the generic type of the node
    pub fn get_generic_type(&self) -> GenericType {
        self.0.borrow().generic_type.clone()
    }
}

/// List of different Node types
enum_from_primitive! {
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum GenericType {
    Unknown = 0x00,
    BasicController = 0x01,
    StaticController = 0x02,
    BasicSlave = 0x03,
    RoutingSlave = 0x04,
    GenericThermostat = 0x08,
    BinarySwitch = 0x10,
    MultiLevelSwitch = 0x11,
    GenericSwitchRemote = 0x12,
    GenericSwitchToggle = 0x13,
    GenericSecurityPanel = 0x17,
    BinarySensor = 0x20,
    MultilevelSensor = 0x21,
    Meter = 0x31,
}
}
<commit_msg>Updated generic device list<commit_after>use controller::Controller;
use cmd_class::basic::Basic;
use std::rc::Rc;
use std::cell::RefCell;
use num::FromPrimitive;
use msg::{Message, Type, Function};

// The private representation of a node
struct _Node {
    id: u8,
    controller: Controller,
    generic_type: GenericType,
    class_basic: Option<Basic>
}

// reference type for the node
type NodeRef = Rc<RefCell<_Node>>;

// The public representation of a node, with some syntactic sugar.
#[derive(Clone)]
pub struct Node(NodeRef);

// The actual node implementation
impl Node {
    /// Creates a new node with no edges.
    pub fn new(contr: Controller, id: u8) -> Node {
        let node = Node(Rc::new(RefCell::new(_Node {
            id: id,
            controller: contr,
            generic_type: GenericType::Unknown,
            class_basic: None
        })));

        node.discover_type();
        node.discover_classes();

        node
    }

    /// Sets the available type for this node
    pub fn discover_type(&self) {
        let mut this = &mut self.0.borrow_mut();

        // create a new message
        let msg = Message::new(Type::Request, Function::GetNodeProtocolInfo, vec!(this.id));

        // send the message to the ZWave driver
        let msg = unwrap_or_return!(this.controller.get_driver().write_and_read(msg).ok(), ());

        //check if the answer has the right length && is no error
        if msg.data.len() != 6 {
            this.generic_type = GenericType::Unknown;
            return;
        }

        // extract the delivered type
        this.generic_type = GenericType::from_u8(msg.data[4]).unwrap_or(GenericType::Unknown);
    }

    /// Sets the available function classes for this node
    pub fn discover_classes(&self) {
        let mut this = &mut self.0.borrow_mut();

        // todo get the information from the device

        // basic is always available
        this.class_basic = Some(Basic::new(self.clone()));
    }

    /// returns the controller
    pub fn get_controller(&self) -> Controller {
        self.0.borrow().controller.clone()
    }

    /// returns the basic command class to interact with
    pub fn get_basic(&self) -> Option<Basic> {
        self.0.borrow_mut().class_basic.clone()
    }

    /// returns the id of the node in the zwave network
    pub fn get_id(&self) -> u8 {
        self.0.borrow().id.clone()
    }

    // returns the generic type of the node
    pub fn get_generic_type(&self) -> GenericType {
        self.0.borrow().generic_type.clone()
    }
}

/// List of different Node types
enum_from_primitive! {
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum GenericType {
    Unknown = 0x00,
    RemoteController = 0x01,
    StaticController = 0x02,
    AvControlPoint = 0x03,
    RoutingSlave = 0x04,
    Display = 0x06,
    GarageDoor = 0x07,
    WindowCovering = 0x09,
    Thermostat = 0x08,
    RepeaterSlave = 0x0F,
    BinarySwitch = 0x10,
    MultiLevelSwitch = 0x11,
    RemoteSwitch = 0x12,
    ToggleSwitch = 0x13,
    ZIpGateway = 0x14,
    ZIpNode = 0x15,
    Ventilation = 0x16,
    GenericSecurityPanel = 0x17,
    RemoteSwitch2 = 0x18,
    BinarySensor = 0x20,
    MultilevelSensor = 0x21,
    WaterControl = 0x22,
    PulseMeter = 0x30,
    Meter = 0x31,
    EntryControl = 0x40,
    SemiInteroperable = 0x50,
    AlarmSensor = 0xa1,
    NonInteroperable = 0xFF,
}
}
<|endoftext|>


<commit_before>use std::iter::Peekable;
use std::str::CharIndices;

use {Error, Result};

pub struct Path;

pub struct Data {
    pub commands: Vec<Command>,
}

#[derive(Debug)]
pub enum Command {
    Invalid,
    MoveTo(Positioning, Vec<f64>),
    ClosePath,
    LineTo(Positioning, Vec<f64>),
    HorizontalLineTo(Positioning, Vec<f64>),
    VerticalLineTo(Positioning, Vec<f64>),
    CurveTo(Positioning, Vec<f64>),
    SmoothCurveTo(Positioning, Vec<f64>),
    QuadraticBezierCurveTo(Positioning, Vec<f64>),
    SmoothQuadraticBezierCurveTo(Positioning, Vec<f64>),
    EllipticalArc(Positioning, Vec<f64>),
}

#[derive(Debug)]
pub enum Positioning {
    Absolute,
    Relative,
}

impl Data {
    #[inline]
    pub fn parse(line: &str) -> Result<Data> {
        DataParser::new(line).process()
    }
}

struct DataParser<'s> {
    line: &'s str,
    position: usize,
    cursor: Peekable<CharIndices<'s>>,
}

macro_rules! ok(
    ($result:expr) => (
        match $result {
            Ok(result) => result,
            Err(error) => return Err(error),
        }
    )
);

macro_rules! raise(
    ($parser:expr, $($arg:tt)*) => (
        return Err(Error {
            line: 1,
            column: $parser.position,
            message: format!($($arg)*),
        })
    );
);

impl<'s> DataParser<'s> {
    fn new(line: &'s str) -> DataParser<'s> {
        DataParser {
            line: line,
            position: 0,
            cursor: line.char_indices().peekable(),
        }
    }

    fn process(&mut self) -> Result<Data> {
        let mut commands = Vec::new();

        loop {
            self.skip_whitespace();

            match ok!(self.read_command()) {
                Some(command) => commands.push(command),
                _ => break,
            }
        }

        Ok(Data {
            commands: commands,
        })
    }

    fn read_command(&mut self) -> Result<Option<Command>> {
        use self::Command::*;
        use self::Positioning::*;

        let name = match self.next() {
            Some(name) => match name {
                'A'...'Z' | 'a'...'z' => name,
                _ => raise!(self, "expected a path command"),
            },
            _ => return Ok(None),
        };

        self.skip_whitespace();

        let params = ok!(self.read_parameters());

        Ok(Some(match name {
            'M' => MoveTo(Absolute, params),
            'm' => MoveTo(Relative, params),

            'Z' | 'z' => ClosePath,

            'L' => LineTo(Absolute, params),
            'l' => LineTo(Relative, params),

            'H' => HorizontalLineTo(Absolute, params),
            'h' => HorizontalLineTo(Relative, params),

            'V' => VerticalLineTo(Absolute, params),
            'v' => VerticalLineTo(Relative, params),

            'C' => CurveTo(Absolute, params),
            'c' => CurveTo(Relative, params),

            'S' => SmoothCurveTo(Absolute, params),
            's' => SmoothCurveTo(Relative, params),

            'Q' => QuadraticBezierCurveTo(Absolute, params),
            'q' => QuadraticBezierCurveTo(Relative, params),

            'T' => SmoothQuadraticBezierCurveTo(Absolute, params),
            't' => SmoothQuadraticBezierCurveTo(Relative, params),

            'A' => EllipticalArc(Absolute, params),
            'a' => EllipticalArc(Relative, params),

            _ => raise!(self, "found an unknown path command '{}'", name),
        }))
    }

    fn read_parameters(&mut self) -> Result<Vec<f64>> {
        let mut params = Vec::new();

        loop {
            match ok!(self.read_number()) {
                Some(number) => params.push(number),
                _ => break,
            }

            self.skip_whitespace();
            self.skip(",");
        }

        Ok(params)
    }

    fn read_number(&mut self) -> Result<Option<f64>> {
        self.skip_whitespace();

        let start = self.position;

        self.skip("-");
        self.skip_digits();
        self.skip(".");
        self.skip_digits();

        let end = self.position;

        if start == end {
            return Ok(None)
        }

        let number = &self.line[start..end];

        match number.parse() {
            Ok(number) => Ok(Some(number)),
            Err(_) => raise!(self, "failed to parse a number '{}'", number),
        }
    }

    #[inline]
    fn skip_whitespace(&mut self) {
        self.skip(" \t")
    }

    #[inline]
    fn skip_digits(&mut self) {
        self.skip("0123456789")
    }

    fn skip(&mut self, chars: &str) {
        loop {
            match self.peek() {
                Some(c) => {
                    if chars.contains_char(c) {
                        self.next();
                    } else {
                        break;
                    }
                },
                _ => break,
            }
        }
    }

    #[inline]
    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some((_, c)) => {
                self.position += 1;
                Some(c)
            },
            _ => None,
        }
    }

    #[inline]
    fn peek(&mut self) -> Option<char> {
        match self.cursor.peek() {
            Some(&(_, c)) => Some(c),
            _ => None,
        }
    }
}

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

    #[test]
    fn data_parser_read_command() {
        macro_rules! run(
            ($line:expr) => ({
                let mut parser = DataParser::new($line);
                parser.read_command().ok().unwrap().unwrap()
            });
        );

        macro_rules! test(
            ($line:expr, $command:ident, $positioning:ident, $params:expr) => (
                match run!($line) {
                    $command($positioning, params) => assert_eq!(params, $params),
                    _ => assert!(false),
                }
            );
        );

        test!("M4,2", MoveTo, Absolute, vec![4.0, 2.0]);
        test!("m4,2", MoveTo, Relative, vec![4.0, 2.0]);

        test!("L7, 8  9", LineTo, Absolute, vec![7.0, 8.0, 9.0]);
        test!("l 7,8 9", LineTo, Relative, vec![7.0, 8.0, 9.0]);

        test!("H\t6,9", HorizontalLineTo, Absolute, vec![6.0, 9.0]);
        test!("h6,  \t9", HorizontalLineTo, Relative, vec![6.0, 9.0]);

        test!("V2.1,-3", VerticalLineTo, Absolute, vec![2.1, -3.0]);
        test!("v2.1 -3", VerticalLineTo, Relative, vec![2.1, -3.0]);

        test!("C0,1 0,2", CurveTo, Absolute, vec![0.0, 1.0, 0.0, 2.0]);
        test!("c0 ,1 0,  2", CurveTo, Relative, vec![0.0, 1.0, 0.0, 2.0]);

        test!("S42,0", SmoothCurveTo, Absolute, vec![42.0, 0.0]);
        test!("s \t 42,0", SmoothCurveTo, Relative, vec![42.0, 0.0]);

        test!("Q90.5 0", QuadraticBezierCurveTo, Absolute, vec![90.5, 0.0]);
        test!("q90.5, 0", QuadraticBezierCurveTo, Relative, vec![90.5, 0.0]);

        test!("T-1", SmoothQuadraticBezierCurveTo, Absolute, vec![-1.0]);
        test!("t -1", SmoothQuadraticBezierCurveTo, Relative, vec![-1.0]);

        test!("A2.6,0 -7", EllipticalArc, Absolute, vec![2.6, 0.0, -7.0]);
        test!("a 2.6 ,0 -7", EllipticalArc, Relative, vec![2.6, 0.0, -7.0]);
    }

    #[test]
    fn data_parser_read_parameters() {
        let mut parser = DataParser::new("1,2 3,4 5 6.7");
        let params = parser.read_parameters().ok().unwrap();
        assert_eq!(params, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.7]);
    }

    #[test]
    fn data_parser_read_number() {
        let lines = vec!["-1", "3", "3.14"];
        let numbers = vec![-1.0, 3.0, 3.14];

        for (line, &number) in lines.iter().zip(numbers.iter()) {
            let mut parser = DataParser::new(line);
            assert_eq!(parser.read_number().ok().unwrap().unwrap(), number);
        }
    }

    #[test]
    fn data_parser_skip_whitespace() {
        let mut parser = DataParser::new(" \t    m ");
        parser.skip_whitespace();
        assert_eq!(parser.position, 6);
    }
}
<commit_msg>Add a test for ClosePath<commit_after>use std::iter::Peekable;
use std::str::CharIndices;

use {Error, Result};

pub struct Path;

pub struct Data {
    pub commands: Vec<Command>,
}

#[derive(Debug)]
pub enum Command {
    Invalid,
    MoveTo(Positioning, Vec<f64>),
    ClosePath,
    LineTo(Positioning, Vec<f64>),
    HorizontalLineTo(Positioning, Vec<f64>),
    VerticalLineTo(Positioning, Vec<f64>),
    CurveTo(Positioning, Vec<f64>),
    SmoothCurveTo(Positioning, Vec<f64>),
    QuadraticBezierCurveTo(Positioning, Vec<f64>),
    SmoothQuadraticBezierCurveTo(Positioning, Vec<f64>),
    EllipticalArc(Positioning, Vec<f64>),
}

#[derive(Debug)]
pub enum Positioning {
    Absolute,
    Relative,
}

impl Data {
    #[inline]
    pub fn parse(line: &str) -> Result<Data> {
        DataParser::new(line).process()
    }
}

struct DataParser<'s> {
    line: &'s str,
    position: usize,
    cursor: Peekable<CharIndices<'s>>,
}

macro_rules! ok(
    ($result:expr) => (
        match $result {
            Ok(result) => result,
            Err(error) => return Err(error),
        }
    )
);

macro_rules! raise(
    ($parser:expr, $($arg:tt)*) => (
        return Err(Error {
            line: 1,
            column: $parser.position,
            message: format!($($arg)*),
        })
    );
);

impl<'s> DataParser<'s> {
    fn new(line: &'s str) -> DataParser<'s> {
        DataParser {
            line: line,
            position: 0,
            cursor: line.char_indices().peekable(),
        }
    }

    fn process(&mut self) -> Result<Data> {
        let mut commands = Vec::new();

        loop {
            self.skip_whitespace();

            match ok!(self.read_command()) {
                Some(command) => commands.push(command),
                _ => break,
            }
        }

        Ok(Data {
            commands: commands,
        })
    }

    fn read_command(&mut self) -> Result<Option<Command>> {
        use self::Command::*;
        use self::Positioning::*;

        let name = match self.next() {
            Some(name) => match name {
                'A'...'Z' | 'a'...'z' => name,
                _ => raise!(self, "expected a path command"),
            },
            _ => return Ok(None),
        };

        self.skip_whitespace();

        let params = ok!(self.read_parameters());

        Ok(Some(match name {
            'M' => MoveTo(Absolute, params),
            'm' => MoveTo(Relative, params),

            'Z' | 'z' => ClosePath,

            'L' => LineTo(Absolute, params),
            'l' => LineTo(Relative, params),

            'H' => HorizontalLineTo(Absolute, params),
            'h' => HorizontalLineTo(Relative, params),

            'V' => VerticalLineTo(Absolute, params),
            'v' => VerticalLineTo(Relative, params),

            'C' => CurveTo(Absolute, params),
            'c' => CurveTo(Relative, params),

            'S' => SmoothCurveTo(Absolute, params),
            's' => SmoothCurveTo(Relative, params),

            'Q' => QuadraticBezierCurveTo(Absolute, params),
            'q' => QuadraticBezierCurveTo(Relative, params),

            'T' => SmoothQuadraticBezierCurveTo(Absolute, params),
            't' => SmoothQuadraticBezierCurveTo(Relative, params),

            'A' => EllipticalArc(Absolute, params),
            'a' => EllipticalArc(Relative, params),

            _ => raise!(self, "found an unknown path command '{}'", name),
        }))
    }

    fn read_parameters(&mut self) -> Result<Vec<f64>> {
        let mut params = Vec::new();

        loop {
            match ok!(self.read_number()) {
                Some(number) => params.push(number),
                _ => break,
            }

            self.skip_whitespace();
            self.skip(",");
        }

        Ok(params)
    }

    fn read_number(&mut self) -> Result<Option<f64>> {
        self.skip_whitespace();

        let start = self.position;

        self.skip("-");
        self.skip_digits();
        self.skip(".");
        self.skip_digits();

        let end = self.position;

        if start == end {
            return Ok(None)
        }

        let number = &self.line[start..end];

        match number.parse() {
            Ok(number) => Ok(Some(number)),
            Err(_) => raise!(self, "failed to parse a number '{}'", number),
        }
    }

    #[inline]
    fn skip_whitespace(&mut self) {
        self.skip(" \t")
    }

    #[inline]
    fn skip_digits(&mut self) {
        self.skip("0123456789")
    }

    fn skip(&mut self, chars: &str) {
        loop {
            match self.peek() {
                Some(c) => {
                    if chars.contains_char(c) {
                        self.next();
                    } else {
                        break;
                    }
                },
                _ => break,
            }
        }
    }

    #[inline]
    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some((_, c)) => {
                self.position += 1;
                Some(c)
            },
            _ => None,
        }
    }

    #[inline]
    fn peek(&mut self) -> Option<char> {
        match self.cursor.peek() {
            Some(&(_, c)) => Some(c),
            _ => None,
        }
    }
}

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

    #[test]
    fn data_parser_read_command() {
        macro_rules! run(
            ($line:expr) => ({
                let mut parser = DataParser::new($line);
                parser.read_command().ok().unwrap().unwrap()
            });
        );

        macro_rules! test(
            ($line:expr, $command:ident, $positioning:ident, $params:expr) => (
                match run!($line) {
                    $command($positioning, params) => assert_eq!(params, $params),
                    _ => assert!(false),
                }
            );
            ($line:expr, $command:ident) => (
                match run!($line) {
                    $command => {},
                    _ => assert!(false),
                }
            );
        );

        test!("M4,2", MoveTo, Absolute, vec![4.0, 2.0]);
        test!("m4,2", MoveTo, Relative, vec![4.0, 2.0]);

        test!("Z", ClosePath);
        test!("z", ClosePath);

        test!("L7, 8  9", LineTo, Absolute, vec![7.0, 8.0, 9.0]);
        test!("l 7,8 9", LineTo, Relative, vec![7.0, 8.0, 9.0]);

        test!("H\t6,9", HorizontalLineTo, Absolute, vec![6.0, 9.0]);
        test!("h6,  \t9", HorizontalLineTo, Relative, vec![6.0, 9.0]);

        test!("V2.1,-3", VerticalLineTo, Absolute, vec![2.1, -3.0]);
        test!("v2.1 -3", VerticalLineTo, Relative, vec![2.1, -3.0]);

        test!("C0,1 0,2", CurveTo, Absolute, vec![0.0, 1.0, 0.0, 2.0]);
        test!("c0 ,1 0,  2", CurveTo, Relative, vec![0.0, 1.0, 0.0, 2.0]);

        test!("S42,0", SmoothCurveTo, Absolute, vec![42.0, 0.0]);
        test!("s \t 42,0", SmoothCurveTo, Relative, vec![42.0, 0.0]);

        test!("Q90.5 0", QuadraticBezierCurveTo, Absolute, vec![90.5, 0.0]);
        test!("q90.5, 0", QuadraticBezierCurveTo, Relative, vec![90.5, 0.0]);

        test!("T-1", SmoothQuadraticBezierCurveTo, Absolute, vec![-1.0]);
        test!("t -1", SmoothQuadraticBezierCurveTo, Relative, vec![-1.0]);

        test!("A2.6,0 -7", EllipticalArc, Absolute, vec![2.6, 0.0, -7.0]);
        test!("a 2.6 ,0 -7", EllipticalArc, Relative, vec![2.6, 0.0, -7.0]);
    }

    #[test]
    fn data_parser_read_parameters() {
        let mut parser = DataParser::new("1,2 3,4 5 6.7");
        let params = parser.read_parameters().ok().unwrap();
        assert_eq!(params, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.7]);
    }

    #[test]
    fn data_parser_read_number() {
        let lines = vec!["-1", "3", "3.14"];
        let numbers = vec![-1.0, 3.0, 3.14];

        for (line, &number) in lines.iter().zip(numbers.iter()) {
            let mut parser = DataParser::new(line);
            assert_eq!(parser.read_number().ok().unwrap().unwrap(), number);
        }
    }

    #[test]
    fn data_parser_skip_whitespace() {
        let mut parser = DataParser::new(" \t    m ");
        parser.skip_whitespace();
        assert_eq!(parser.position, 6);
    }
}
<|endoftext|>


<commit_before>//! POET - the Performance with Optimal Energy Toolkit. Used to meet timing constraints while
//! minimizing energy consumption.

use libc::{c_void, c_char, c_int, c_uint, c_double};
use std::ffi::CString;
use std::ptr;

/// Typedef for an "apply" function - used to manipulate system or application settings.
pub type POETApplyFn = unsafe extern fn(states: *mut c_void,
                                        num_states: c_uint,
                                        id: c_uint,
                                        last_id: c_uint);

/// Typedef for "current state" function - used to try and determine the current system or
/// application state.
pub type POETCurrentStateFn = unsafe extern fn(states: *const c_void,
                                               num_states: c_uint,
                                               curr_state_id: *mut c_uint) -> i32;

#[link(name = "poet")]
extern {
    /*
     * Core functions - poet.h
     */

    fn poet_init(perf_goal: c_double,
                 num_system_states: c_uint,
                 control_states: *mut POETControlState,
                 apply_states: *mut POETCpuState,
                 apply_func: POETApplyFn,
                 curr_state_func: POETCurrentStateFn,
                 period: c_uint,
                 buffer_depth: c_uint,
                 log_filename: *const c_char) -> *mut c_void;

    fn poet_apply_control(state: *mut c_void,
                          id: u64,
                          perf: c_double,
                          pwr: c_double);

    fn poet_destroy(state: *mut c_void);

    /*
     * Configuration/utility functions - poet_config.h
     */

    fn apply_cpu_config(states: *mut c_void,
                        num_states: c_uint,
                        id: c_uint,
                        last_id: c_uint);

    fn get_control_states(path: *const c_char,
                          states: *mut *mut POETControlState,
                          num_states: *mut c_uint) -> c_int;

    fn get_cpu_states(path: *const c_char,
                      states: *mut *mut POETCpuState,
                      num_states: *mut c_uint) -> c_int;

    fn get_current_cpu_state(states: *const c_void,
                             num_states: c_uint,
                             curr_state_id: *mut c_uint) -> c_int;

}

#[repr(C)]
/// Representation of native struct `poet_control_state_t`.
pub struct POETControlState {
    pub id: c_uint,
    pub speedup: c_double,
    pub cost: c_double,
}

impl POETControlState {
    /// Attempt to load control states from a file.
    pub fn new(filename: Option<&str>) -> Result<(*mut POETControlState, u32), &'static str> {
        let filename = match filename {
            Some(f) => CString::new(f).unwrap().as_ptr(),
            None => ptr::null(),
        };
        let mut control_states = ptr::null_mut();
        let mut num_ctl_states : u32 = 0;
        let res = unsafe {
            get_control_states(filename,
                               &mut control_states,
                               &mut num_ctl_states)
        };
        if res != 0 {
            return Err("Failed to load control states");
        }
        Ok((control_states, num_ctl_states))
    }
}

impl Default for POETControlState {
    fn default() -> POETControlState {
        POETControlState {
            id: 0,
            speedup: 1.0,
            cost: 1.0,
        }
    }
}

#[repr(C)]
/// Representation of native struct `poet_cpu_state_t`.
pub struct POETCpuState {
    id: c_uint,
    freq: c_uint,
    cores: c_uint,
}

impl POETCpuState {
    /// Attempt to load cpu states from a file.
    pub fn new(filename: Option<&str>) -> Result<(*mut POETCpuState, u32), &'static str> {
        let filename = match filename {
            Some(f) => CString::new(f).unwrap().as_ptr(),
            None => ptr::null(),
        };
        let mut cpu_states = ptr::null_mut();
        let mut num_cpu_states : u32 = 0;
        let res = unsafe {
            get_cpu_states(filename,
                           &mut cpu_states,
                           &mut num_cpu_states)
        };
        if res != 0 {
            return Err("Failed to load cpu states");
        }
        Ok((cpu_states, num_cpu_states))
    }
}

impl Default for POETCpuState {
    fn default() -> POETCpuState {
        POETCpuState {
            id: 0,
            freq: 0,
            cores: 0,
        }
    }
}

/// The `POET` struct wraps an underyling C struct.
pub struct POET {
    /// The underlying C struct `poet_state`.
    pub poet: *mut c_void,
}

impl POET {
    /// Attempt to initialize POET and allocate resources in the underlying C struct.
    pub fn new(perf_goal: f64,
               control_states: *mut POETControlState,
               cpu_states: *mut POETCpuState,
               num_states: u32,
               apply_func: Option<POETApplyFn>,
               curr_state_func: Option<POETCurrentStateFn>,
               period: u32,
               buffer_depth: u32,
               log_filename: Option<&str>) -> Result<POET, &'static str> {
        let apply_func = match apply_func {
            Some(p) => p,
            None => apply_cpu_config,
        };
        let curr_state_func = match curr_state_func {
            Some(p) => p,
            None => get_current_cpu_state,
        };
        let log_filename = match log_filename {
            Some(l) => CString::new(l).unwrap().as_ptr(),
            None => ptr::null(),
        };
        let poet = unsafe {
            poet_init(perf_goal,
                      num_states, control_states, cpu_states,
                      apply_func, curr_state_func,
                      period, buffer_depth, log_filename)
        };
        if poet.is_null() {
            return Err("Failed to instantiate POET object");
        }
        Ok(POET { poet: poet, })
    }

    /// Call at every iteration - at specified periods this function will (potentially) order
    /// changes to system or application state to try and meet timing constraints.
    pub fn apply_control(&mut self, tag: u64, window_rate: f64, window_power: f64) {
        unsafe {
            poet_apply_control(self.poet, tag, window_rate, window_power);
        }
    }
}

impl Drop for POET {
    /// Cleanup POET and deallocate resources in the underlying C struct.
    fn drop(&mut self) {
        unsafe {
            poet_destroy(self.poet);
        }
        println!("Cleaned up POET");
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libc::{c_void, c_uint};

    #[test]
    fn test_basic() {
        let mut control_states = vec![POETControlState::default()];
        let mut cpu_states = vec![POETCpuState::default()];
        let mut poet = POET::new(100.0,
                                 control_states.as_mut_ptr(), cpu_states.as_mut_ptr(), 1,
                                 None, None,
                                 20u32, 1u32, None).unwrap();
        poet.apply_control(0, 1.0, 1.0);
    }

    #[test]
    fn test_rust_callbacks() {
        let mut control_states = vec![POETControlState::default()];
        let mut cpu_states = vec![POETCpuState::default()];
        let mut poet = POET::new(100.0,
                                 control_states.as_mut_ptr(), cpu_states.as_mut_ptr(), 1,
                                 Some(dummy_apply), Some(dummy_curr_state),
                                 20u32, 1u32, None).unwrap();
        for i in 0..50 {
            poet.apply_control(i, 1.0, 1.0);
        }
    }

    unsafe extern fn dummy_apply(_states: *mut c_void,
                                 _num_states: c_uint,
                                 _id: c_uint,
                                 _last_id: c_uint) {
        // do nothing
        println!("Received apply call");
    }

    unsafe extern fn dummy_curr_state (_states: *const c_void,
                                       _num_states: c_uint,
                                       _curr_state_id: *mut c_uint) -> i32 {
        println!("Received curr state call");
        // this is actually an invalid value, but forces the apply function to be called
        *_curr_state_id = _num_states;
        0
    }

}
<commit_msg>Change handling of control and cpu states<commit_after>//! POET - the Performance with Optimal Energy Toolkit. Used to meet timing constraints while
//! minimizing energy consumption.

use libc::{c_void, c_char, c_int, c_uint, c_double};
use std::ffi::CString;
use std::ptr;

/// Typedef for an "apply" function - used to manipulate system or application settings.
pub type POETApplyFn = unsafe extern fn(states: *mut c_void,
                                        num_states: c_uint,
                                        id: c_uint,
                                        last_id: c_uint);

/// Typedef for "current state" function - used to try and determine the current system or
/// application state.
pub type POETCurrentStateFn = unsafe extern fn(states: *const c_void,
                                               num_states: c_uint,
                                               curr_state_id: *mut c_uint) -> i32;

#[link(name = "poet")]
extern {
    /*
     * Core functions - poet.h
     */

    fn poet_init(perf_goal: c_double,
                 num_system_states: c_uint,
                 control_states: *mut POETControlState,
                 apply_states: *mut POETCpuState,
                 apply_func: POETApplyFn,
                 curr_state_func: POETCurrentStateFn,
                 period: c_uint,
                 buffer_depth: c_uint,
                 log_filename: *const c_char) -> *mut c_void;

    fn poet_apply_control(state: *mut c_void,
                          id: u64,
                          perf: c_double,
                          pwr: c_double);

    fn poet_destroy(state: *mut c_void);

    /*
     * Configuration/utility functions - poet_config.h
     */

    fn apply_cpu_config(states: *mut c_void,
                        num_states: c_uint,
                        id: c_uint,
                        last_id: c_uint);

    fn get_control_states(path: *const c_char,
                          states: *mut *mut POETControlState,
                          num_states: *mut c_uint) -> c_int;

    fn get_cpu_states(path: *const c_char,
                      states: *mut *mut POETCpuState,
                      num_states: *mut c_uint) -> c_int;

    fn get_current_cpu_state(states: *const c_void,
                             num_states: c_uint,
                             curr_state_id: *mut c_uint) -> c_int;

}

#[repr(C)]
#[derive(Copy, Clone)]
/// Representation of native struct `poet_control_state_t`.
pub struct POETControlState {
    pub id: c_uint,
    pub speedup: c_double,
    pub cost: c_double,
}

impl POETControlState {
    /// Attempt to load control states from a file.
    pub fn new(filename: Option<&str>) -> Result<Vec<POETControlState>, &'static str> {
        let filename = match filename {
            Some(f) => CString::new(f).unwrap().as_ptr(),
            None => ptr::null(),
        };
        let mut states: *mut POETControlState = ptr::null_mut::<POETControlState>();
        unsafe {
            let mut nstates: u32 = 0;
            let res = get_control_states(filename,
                                         &mut states,
                                         &mut nstates);
            if res != 0 {
                return Err("Failed to load control states");
            }
            let csvec: Vec<POETControlState> = Vec::from_raw_parts(states, nstates as usize, nstates as usize);
            Ok(csvec)
        }
    }
}

impl Default for POETControlState {
    fn default() -> POETControlState {
        POETControlState {
            id: 0,
            speedup: 1.0,
            cost: 1.0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
/// Representation of native struct `poet_cpu_state_t`.
pub struct POETCpuState {
    id: c_uint,
    freq: c_uint,
    cores: c_uint,
}

impl POETCpuState {
    /// Attempt to load cpu states from a file.
    pub fn new(filename: Option<&str>) -> Result<Vec<POETCpuState>, &'static str> {
        let filename = match filename {
            Some(f) => CString::new(f).unwrap().as_ptr(),
            None => ptr::null(),
        };
        let mut states: *mut POETCpuState = ptr::null_mut::<POETCpuState>();
        unsafe {
            let mut nstates: u32 = 0;
            let res = get_cpu_states(filename,
                                     &mut states,
                                     &mut nstates);
            if res != 0 {
                return Err("Failed to load cpu states");
            }
            let csvec: Vec<POETCpuState> = Vec::from_raw_parts(states, nstates as usize, nstates as usize);
            Ok(csvec)
        }
    }
}

impl Default for POETCpuState {
    fn default() -> POETCpuState {
        POETCpuState {
            id: 0,
            freq: 0,
            cores: 0,
        }
    }
}

/// The `POET` struct wraps an underyling C struct.
pub struct POET {
    /// The underlying C struct `poet_state`.
    pub poet: *mut c_void,
}

impl POET {
    /// Attempt to initialize POET and allocate resources in the underlying C struct.
    pub fn new(perf_goal: f64,
               control_states: &mut Vec<POETControlState>,
               cpu_states: &mut Vec<POETCpuState>,
               apply_func: Option<POETApplyFn>,
               curr_state_func: Option<POETCurrentStateFn>,
               period: u32,
               buffer_depth: u32,
               log_filename: Option<&str>) -> Result<POET, &'static str> {
        if control_states.len() != cpu_states.len() {
            return Err("Number of control and cpu states don't match");
        }
        let apply_func = match apply_func {
            Some(p) => p,
            None => apply_cpu_config,
        };
        let curr_state_func = match curr_state_func {
            Some(p) => p,
            None => get_current_cpu_state,
        };
        let log_filename = match log_filename {
            Some(l) => CString::new(l).unwrap().as_ptr(),
            None => ptr::null(),
        };
        let poet = unsafe {
            let num_states = control_states.len() as u32;
            poet_init(perf_goal,
                      num_states, control_states.as_mut_ptr(), cpu_states.as_mut_ptr(),
                      apply_func, curr_state_func,
                      period, buffer_depth, log_filename)
        };
        if poet.is_null() {
            return Err("Failed to instantiate POET object");
        }
        Ok(POET { poet: poet, })
    }

    /// Call at every iteration - at specified periods this function will (potentially) order
    /// changes to system or application state to try and meet timing constraints.
    pub fn apply_control(&mut self, tag: u64, window_rate: f64, window_power: f64) {
        unsafe {
            poet_apply_control(self.poet, tag, window_rate, window_power);
        }
    }
}

impl Drop for POET {
    /// Cleanup POET and deallocate resources in the underlying C struct.
    fn drop(&mut self) {
        unsafe {
            poet_destroy(self.poet);
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libc::{c_void, c_uint};

    #[test]
    fn test_basic() {
        let mut control_states = vec![POETControlState::default()];
        let mut cpu_states = vec![POETCpuState::default()];
        let mut poet = POET::new(100.0,
                                 &mut control_states, &mut cpu_states,
                                 None, None,
                                 20u32, 1u32, Some("poet.log")).unwrap();
        poet.apply_control(0, 1.0, 1.0);
    }

    #[test]
    fn test_rust_callbacks() {
        let mut control_states = vec![POETControlState::default()];
        let mut cpu_states = vec![POETCpuState::default()];
        let mut poet = POET::new(100.0,
                                 &mut control_states, &mut cpu_states,
                                 Some(dummy_apply), Some(dummy_curr_state),
                                 20u32, 1u32, None).unwrap();
        for i in 0..50 {
            poet.apply_control(i, 1.0, 1.0);
        }
    }

    unsafe extern fn dummy_apply(_states: *mut c_void,
                                 _num_states: c_uint,
                                 _id: c_uint,
                                 _last_id: c_uint) {
        // do nothing
        println!("Received apply call");
    }

    unsafe extern fn dummy_curr_state (_states: *const c_void,
                                       _num_states: c_uint,
                                       _curr_state_id: *mut c_uint) -> i32 {
        println!("Received curr state call");
        // this is actually an invalid value, but forces the apply function to be called
        *_curr_state_id = _num_states;
        0
    }

}
<|endoftext|>


<commit_before>use expression::Expression;
use helper_types::Select;
use query_dsl::SelectDsl;
use super::delete_statement::DeleteStatement;
use super::insert_statement::Insert;
use super::{IntoUpdateTarget, IncompleteUpdateStatement, IncompleteInsertStatement, SelectStatement};

/// Creates an update statement. Helpers for updating a single row can be
/// generated by deriving [`AsChangeset`](query_builder/trait.AsChangeset.html)
///
/// # Examples
///
/// ### Updating a single record:
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # #[cfg(feature = "postgres")]
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// let updated_row = diesel::update(users.filter(id.eq(1)))
///     .set(name.eq("James"))
///     .get_result(&connection);
/// // On backends that support it, you can call `get_result` instead of `execute`
/// // to have `RETURNING *` automatically appended to the query. Alternatively, you
/// // can explicitly return an expression by using the `returning` method before
/// // getting the result.
/// assert_eq!(Ok((1, "James".to_string())), updated_row);
/// # }
/// # #[cfg(not(feature = "postgres"))]
/// # fn main() {}
/// ```
pub fn update<T: IntoUpdateTarget>(source: T) -> IncompleteUpdateStatement<T::Table, T::WhereClause> {
    IncompleteUpdateStatement::new(source.into_update_target())
}

/// Creates a delete statement. Will delete the records in the given set.
/// Because this function has a very generic name, it is not exported by
/// default.
///
/// # Examples
///
/// ### Deleting a single record:
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     delete();
/// # }
/// #
/// # fn delete() -> QueryResult<()> {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection);
/// let old_count = get_count();
/// try!(diesel::delete(users.filter(id.eq(1))).execute(&connection));
/// assert_eq!(old_count.map(|count| count - 1), get_count());
/// # Ok(())
/// # }
/// ```
///
/// ### Deleting a whole table:
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     delete();
/// # }
/// #
/// # fn delete() -> QueryResult<()> {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection);
/// try!(diesel::delete(users).execute(&connection));
/// assert_eq!(Ok(0), get_count());
/// # Ok(())
/// # }
/// ```
pub fn delete<T: IntoUpdateTarget>(source: T) -> DeleteStatement<T::Table, T::WhereClause> {
    let target = source.into_update_target();
    DeleteStatement::new(target.table, target.where_clause)
}

/// Creates an insert statement. Will add the given data to a table. This
/// function is not exported by default. As with other commands, the resulting
/// query can return the inserted rows if you choose.
pub fn insert<T: ?Sized>(records: &T) -> IncompleteInsertStatement<&T, Insert> {
    IncompleteInsertStatement::new(records, Insert)
}

/// Creates a bare select statement, with no from clause. Primarily used for
/// testing diesel itself, but likely useful for third party crates as well. The
/// given expressions must be selectable from anywhere.
pub fn select<T>(expression: T) -> Select<SelectStatement<()>, T> where
    T: Expression,
    SelectStatement<()>: SelectDsl<T>,
{
    SelectStatement::simple(()).select(expression)
}
<commit_msg>doc: show example of updating multiple values<commit_after>use expression::Expression;
use helper_types::Select;
use query_dsl::SelectDsl;
use super::delete_statement::DeleteStatement;
use super::insert_statement::Insert;
use super::{IntoUpdateTarget, IncompleteUpdateStatement, IncompleteInsertStatement, SelectStatement};

/// Creates an update statement. Helpers for updating a single row can be
/// generated by deriving [`AsChangeset`](query_builder/trait.AsChangeset.html)
///
/// # Examples
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # #[cfg(feature = "postgres")]
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// let updated_row = diesel::update(users.filter(id.eq(1)))
///     .set(name.eq("James"))
///     .get_result(&connection);
/// // On backends that support it, you can call `get_result` instead of `execute`
/// // to have `RETURNING *` automatically appended to the query. Alternatively, you
/// // can explicitly return an expression by using the `returning` method before
/// // getting the result.
/// assert_eq!(Ok((1, "James".to_string())), updated_row);
/// # }
/// # #[cfg(not(feature = "postgres"))]
/// # fn main() {}
/// ```
///
/// To update multiple columns, give `set` a tuple argument:
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #         surname -> VarChar,
/// #     }
/// # }
/// #
/// # #[cfg(feature = "postgres")]
/// # fn main() {
/// # use users::dsl::*;
/// # let connection = establish_connection();
/// # connection.execute("DROP TABLE users").unwrap();
/// # connection.execute("CREATE TABLE users (
/// #     id SERIAL PRIMARY KEY,
/// #     name VARCHAR,
/// #     surname VARCHAR)").unwrap();
/// # connection.execute("INSERT INTO users(name, surname) VALUES('Sean', 'Griffin')").unwrap();
///
/// let updated_row = diesel::update(users.filter(id.eq(1)))
///     .set((name.eq("James"), surname.eq("Bond")))
///     .get_result(&connection);
///
/// assert_eq!(Ok((1, "James".to_string(), "Bond".to_string())), updated_row);
/// # }
/// # #[cfg(not(feature = "postgres"))]
/// # fn main() {}
/// ```
pub fn update<T: IntoUpdateTarget>(source: T) -> IncompleteUpdateStatement<T::Table, T::WhereClause> {
    IncompleteUpdateStatement::new(source.into_update_target())
}

/// Creates a delete statement. Will delete the records in the given set.
/// Because this function has a very generic name, it is not exported by
/// default.
///
/// # Examples
///
/// ### Deleting a single record:
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     delete();
/// # }
/// #
/// # fn delete() -> QueryResult<()> {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection);
/// let old_count = get_count();
/// try!(diesel::delete(users.filter(id.eq(1))).execute(&connection));
/// assert_eq!(old_count.map(|count| count - 1), get_count());
/// # Ok(())
/// # }
/// ```
///
/// ### Deleting a whole table:
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     delete();
/// # }
/// #
/// # fn delete() -> QueryResult<()> {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     let get_count = || users.count().first::<i64>(&connection);
/// try!(diesel::delete(users).execute(&connection));
/// assert_eq!(Ok(0), get_count());
/// # Ok(())
/// # }
/// ```
pub fn delete<T: IntoUpdateTarget>(source: T) -> DeleteStatement<T::Table, T::WhereClause> {
    let target = source.into_update_target();
    DeleteStatement::new(target.table, target.where_clause)
}

/// Creates an insert statement. Will add the given data to a table. This
/// function is not exported by default. As with other commands, the resulting
/// query can return the inserted rows if you choose.
pub fn insert<T: ?Sized>(records: &T) -> IncompleteInsertStatement<&T, Insert> {
    IncompleteInsertStatement::new(records, Insert)
}

/// Creates a bare select statement, with no from clause. Primarily used for
/// testing diesel itself, but likely useful for third party crates as well. The
/// given expressions must be selectable from anywhere.
pub fn select<T>(expression: T) -> Select<SelectStatement<()>, T> where
    T: Expression,
    SelectStatement<()>: SelectDsl<T>,
{
    SelectStatement::simple(()).select(expression)
}
<|endoftext|>


<commit_before>use snappy;
use std::cmp::min;
use std::io::{self, Read};

use buffer::Buffer;
use consts::*;
use masked_crc::*;

/// Should we verify or ignore the CRC when reading?
#[derive(Debug, PartialEq, Eq)]
pub enum CrcMode {
    Verify,
    Ignore
}

/// A framed chunk in a Snappy stream.
#[derive(Debug)]
struct Chunk<'a> {
    chunk_type: u8,
    data: &'a [u8]
}

impl<'a> Chunk<'a> {
    fn crc(&self) -> io::Result<u32> {
        if self.data.len() < CRC_SIZE {
            Err(io::Error::new(io::ErrorKind::Other, "Snappy CRC truncated"))
        } else {
            Ok((self.data[0] as u32) |
               (self.data[1] as u32) << 8 |
               (self.data[2] as u32) << 16 |
               (self.data[3] as u32) << 24)
        }
    }
}

fn check_crc(expected: u32, data: &[u8]) -> io::Result<()> {
    let actual = masked_crc(data);
    if expected == actual {
        Ok(())
    } else {
        Err(io::Error::new(io::ErrorKind::Other,
                           format!("Invalid Snappy CRC (expected {:x}, got {:x})",
                                   expected, actual)))
    }
}

// Add some input-related convenience functions to Buffer.  We can't put
// these in the `SnappyFramedDecoder` itself because they return references
// to our internal buffer, and thereby render it unavailable until we're
// done.  But if we render `SnappyFramedDecoder` unavailable, we can't
// write to our output buffer.  So it's better to keep this separate.
impl Buffer {
    /// Make sure we have at least the specified number of bytes buffered.
    fn ensure_buffered<R: Read>(&mut self, bytes: usize, source: &mut R) ->
        io::Result<Option<&[u8]>>
    {
        // If we don't have enough data buffered, go get more.
        if self.buffered() < bytes {
            // If our input buffer is too small to hold a chunk, resize it.
            // This should never fire for reasonable input files, so we're not
            // concerned about speed.
            let capacity = self.capacity();
            if bytes > capacity {
                warn!("Snappy chunk of {} bytes required growing buffer", bytes);
                self.add_capacity(bytes - capacity);
            }

            // Move any partial data to the start of the buffer.
            self.move_data_to_start();

            // Try to fill up our buffer.
            loop {
                let bytes_read = {
                    let space = self.space_to_fill();
                    if space.len() == 0 { break; /* Full. */ }
                    try!(source.read(space))
                };
                self.added(bytes_read);
                if bytes_read == 0 { break; /* No more, at least for now. */ }
            }

            // Decide what to do if we still don't have enough data.
            if self.buffered() == 0 {
                // No data, so we're presumably at the end of the file.
                // Return nothing.
                return Ok(None);
            } else if self.buffered() < bytes {
                // Partial data, so fail with an error.
                return Err(io::Error::new(io::ErrorKind::Other,
                                          "Incomplete Snappy chunk"));
            }
        }

        // Actually return our bytes.
        Ok(Some(self.consume(bytes)))
    }

    /// Read in the next input chunk.
    fn next_chunk<R: Read>(&mut self, source: &mut R) ->
        io::Result<Option<Chunk>>
    {
        let (chunk_type, chunk_len) = {
            match try!(self.ensure_buffered(HEADER_SIZE, source)) {
                None => return Ok(None),
                Some(chunk_header) => {
                    (chunk_header[0],
                     ((chunk_header[3] as usize) << 16 |
                      (chunk_header[2] as usize) << 8 |
                      (chunk_header[1] as usize)))
                }
            }
        };
        let data = try!(self.ensure_buffered(chunk_len, source))
            .expect("Snappy chunk header with missing data");
        Ok(Some(Chunk{chunk_type: chunk_type, data: data}))
    }
}

/// Decode a stream containing Snappy-compressed frames.
pub struct SnappyFramedDecoder<R: Read> {
    source: R,
    input: Buffer,
    output: Buffer,
    mode: CrcMode
}

impl<R: Read> SnappyFramedDecoder<R> {
    pub fn new(source: R, mode: CrcMode) -> Self {
        SnappyFramedDecoder{
            source: source,
            input: Buffer::new(1024*1024),
            output: Buffer::new(MAX_UNCOMPRESSED_CHUNK),
            mode: mode
        }
    }
}

impl<R: Read> Read for SnappyFramedDecoder<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if self.output.empty() {
            loop {
                match try!(self.input.next_chunk(&mut self.source)) {
                    None => return Ok(0),
                    Some(chunk) => {
                        //println!("chunk: {:?}", chunk);
                        match chunk.chunk_type {
                            // Compressed data.
                            0x00 => {
                                // TODO: Output size check.
                                // TODO: Malformed data check.
                                let crc = try!(chunk.crc());
                                let compressed = &chunk.data[CRC_SIZE..];
                                let data = snappy::uncompress(compressed)
                                    .expect("Snappy decompression failure");
                                if self.mode == CrcMode::Verify {
                                    try!(check_crc(crc, &data));
                                }
                                self.output.set_data(&data);
                                break;
                            }

                            // Uncompressed data.
                            0x01 => {
                                // TODO: Output size check.
                                // TODO: Malformed data check.
                                let crc = try!(chunk.crc());
                                let data = &chunk.data[CRC_SIZE..];
                                if self.mode == CrcMode::Verify {
                                    try!(check_crc(crc, &data));
                                }
                                self.output.set_data(&data);
                                break;
                            }

                            // Reserved unskippable chunks.
                            0x02...0x7F => {}
                            // Reserved skippable chunks.
                            0x80...0xFD => {}
                            // Padding.
                            0xFE => {}
                            // Stream identifier.
                            0xFF => {}
                            _ => unreachable!()
                        }
                    }
                }
            }
        }

        let to_copy = min(self.output.buffered(), buf.len());
        self.output.copy_out_and_consume(to_copy, buf);
        Ok(to_copy)
    }
}

#[cfg(test)]
fn large_compressed_data(repeats: usize) -> io::Result<Vec<u8>> {
    use std::io::Write;

    use write::SnappyFramedEncoder;
    use test_helpers::*;

    // Build a large vector containing repeated text data.
    let hunk = try!(read_file("data/arbres.txt"));
    let data = repeat_data(&hunk, repeats);

    // Compress it.
    let mut compressed = vec!();
    {
        let mut compressor = try!(SnappyFramedEncoder::new(&mut compressed));
        let written = try!(compressor.write(&data));
        assert_eq!(data.len(), written);
        try!(compressor.flush());
    }
    Ok(compressed)
}

#[test]
fn decode_example_stream() {
    use std::fs::File;
    use dribble::DribbleReader;

    use test_helpers::*;

    let mut compressed = File::open("data/arbres.txt.sz").unwrap();
    let mut dribble = DribbleReader::new(&mut compressed);
    let mut decompressor = SnappyFramedDecoder::new(&mut dribble,
                                                    CrcMode::Verify);
    let mut decompressed = vec!();
    decompressor.read_to_end(&mut decompressed).unwrap();

    let expected = read_file("data/arbres.txt").unwrap();
    assert_eq!(expected, decompressed);
}

#[test]
fn encode_and_decode_large_data() {
    use std::io::Cursor;

    use test_helpers::*;

    // Build a multi-MB vector containing text data.
    let hunk = read_file("data/arbres.txt").unwrap();
    let input = repeat_data(&hunk, 1000);
    let compressed = large_compressed_data(1000).unwrap();

    // Decode it.
    let mut cursor = Cursor::new(&compressed as &[u8]);
    let mut decompressor = SnappyFramedDecoder::new(&mut cursor,
                                                    CrcMode::Verify);
    let mut decompressed = vec!();
    decompressor.read_to_end(&mut decompressed).unwrap();

    // Compare it.
    assert_eq!(input, decompressed);
}

// Test for invalid inputs:
//   - No identifier chunk.
//   - Incomplete chunks: All positions return errors.
//   - Reserved chunk types.
//   - Bad CRC.
//   - Overlong chunks (both compressed--two variants--and uncompressed).

#[cfg(all(test, feature = "unstable"))]
mod benches {
    use std::io::{Cursor, Read};
    use test::Bencher;

    use super::{CrcMode, SnappyFramedDecoder, large_compressed_data};

    #[bench]
    fn decompress_speed(b: &mut Bencher) {
        let data = large_compressed_data(50).unwrap();

        let mut output_bytes = 0;
        let mut buffer = vec![0; 128*1024];
        b.iter(|| {
            output_bytes = 0;
            {
                let mut cursor = Cursor::new(&data as &[u8]);
                let mut decoder = SnappyFramedDecoder::new(&mut cursor,
                                                           CrcMode::Ignore);
                loop {
                    let bytes_read = decoder.read(&mut buffer).unwrap();
                    output_bytes += bytes_read;
                    if bytes_read == 0 { break; }
                }
            }
            buffer[0]
        });
        b.bytes = output_bytes as u64;
    }
}
<commit_msg>Boost benchmark data size back up (now 765 MB/s!)<commit_after>use snappy;
use std::cmp::min;
use std::io::{self, Read};

use buffer::Buffer;
use consts::*;
use masked_crc::*;

/// Should we verify or ignore the CRC when reading?
#[derive(Debug, PartialEq, Eq)]
pub enum CrcMode {
    Verify,
    Ignore
}

/// A framed chunk in a Snappy stream.
#[derive(Debug)]
struct Chunk<'a> {
    chunk_type: u8,
    data: &'a [u8]
}

impl<'a> Chunk<'a> {
    fn crc(&self) -> io::Result<u32> {
        if self.data.len() < CRC_SIZE {
            Err(io::Error::new(io::ErrorKind::Other, "Snappy CRC truncated"))
        } else {
            Ok((self.data[0] as u32) |
               (self.data[1] as u32) << 8 |
               (self.data[2] as u32) << 16 |
               (self.data[3] as u32) << 24)
        }
    }
}

fn check_crc(expected: u32, data: &[u8]) -> io::Result<()> {
    let actual = masked_crc(data);
    if expected == actual {
        Ok(())
    } else {
        Err(io::Error::new(io::ErrorKind::Other,
                           format!("Invalid Snappy CRC (expected {:x}, got {:x})",
                                   expected, actual)))
    }
}

// Add some input-related convenience functions to Buffer.  We can't put
// these in the `SnappyFramedDecoder` itself because they return references
// to our internal buffer, and thereby render it unavailable until we're
// done.  But if we render `SnappyFramedDecoder` unavailable, we can't
// write to our output buffer.  So it's better to keep this separate.
impl Buffer {
    /// Make sure we have at least the specified number of bytes buffered.
    fn ensure_buffered<R: Read>(&mut self, bytes: usize, source: &mut R) ->
        io::Result<Option<&[u8]>>
    {
        // If we don't have enough data buffered, go get more.
        if self.buffered() < bytes {
            // If our input buffer is too small to hold a chunk, resize it.
            // This should never fire for reasonable input files, so we're not
            // concerned about speed.
            let capacity = self.capacity();
            if bytes > capacity {
                warn!("Snappy chunk of {} bytes required growing buffer", bytes);
                self.add_capacity(bytes - capacity);
            }

            // Move any partial data to the start of the buffer.
            self.move_data_to_start();

            // Try to fill up our buffer.
            loop {
                let bytes_read = {
                    let space = self.space_to_fill();
                    if space.len() == 0 { break; /* Full. */ }
                    try!(source.read(space))
                };
                self.added(bytes_read);
                if bytes_read == 0 { break; /* No more, at least for now. */ }
            }

            // Decide what to do if we still don't have enough data.
            if self.buffered() == 0 {
                // No data, so we're presumably at the end of the file.
                // Return nothing.
                return Ok(None);
            } else if self.buffered() < bytes {
                // Partial data, so fail with an error.
                return Err(io::Error::new(io::ErrorKind::Other,
                                          "Incomplete Snappy chunk"));
            }
        }

        // Actually return our bytes.
        Ok(Some(self.consume(bytes)))
    }

    /// Read in the next input chunk.
    fn next_chunk<R: Read>(&mut self, source: &mut R) ->
        io::Result<Option<Chunk>>
    {
        let (chunk_type, chunk_len) = {
            match try!(self.ensure_buffered(HEADER_SIZE, source)) {
                None => return Ok(None),
                Some(chunk_header) => {
                    (chunk_header[0],
                     ((chunk_header[3] as usize) << 16 |
                      (chunk_header[2] as usize) << 8 |
                      (chunk_header[1] as usize)))
                }
            }
        };
        let data = try!(self.ensure_buffered(chunk_len, source))
            .expect("Snappy chunk header with missing data");
        Ok(Some(Chunk{chunk_type: chunk_type, data: data}))
    }
}

/// Decode a stream containing Snappy-compressed frames.
pub struct SnappyFramedDecoder<R: Read> {
    source: R,
    input: Buffer,
    output: Buffer,
    mode: CrcMode
}

impl<R: Read> SnappyFramedDecoder<R> {
    pub fn new(source: R, mode: CrcMode) -> Self {
        SnappyFramedDecoder{
            source: source,
            input: Buffer::new(1024*1024),
            output: Buffer::new(MAX_UNCOMPRESSED_CHUNK),
            mode: mode
        }
    }
}

impl<R: Read> Read for SnappyFramedDecoder<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if self.output.empty() {
            loop {
                match try!(self.input.next_chunk(&mut self.source)) {
                    None => return Ok(0),
                    Some(chunk) => {
                        //println!("chunk: {:?}", chunk);
                        match chunk.chunk_type {
                            // Compressed data.
                            0x00 => {
                                // TODO: Output size check.
                                // TODO: Malformed data check.
                                let crc = try!(chunk.crc());
                                let compressed = &chunk.data[CRC_SIZE..];
                                let data = snappy::uncompress(compressed)
                                    .expect("Snappy decompression failure");
                                if self.mode == CrcMode::Verify {
                                    try!(check_crc(crc, &data));
                                }
                                self.output.set_data(&data);
                                break;
                            }

                            // Uncompressed data.
                            0x01 => {
                                // TODO: Output size check.
                                // TODO: Malformed data check.
                                let crc = try!(chunk.crc());
                                let data = &chunk.data[CRC_SIZE..];
                                if self.mode == CrcMode::Verify {
                                    try!(check_crc(crc, &data));
                                }
                                self.output.set_data(&data);
                                break;
                            }

                            // Reserved unskippable chunks.
                            0x02...0x7F => {}
                            // Reserved skippable chunks.
                            0x80...0xFD => {}
                            // Padding.
                            0xFE => {}
                            // Stream identifier.
                            0xFF => {}
                            _ => unreachable!()
                        }
                    }
                }
            }
        }

        let to_copy = min(self.output.buffered(), buf.len());
        self.output.copy_out_and_consume(to_copy, buf);
        Ok(to_copy)
    }
}

#[cfg(test)]
fn large_compressed_data(repeats: usize) -> io::Result<Vec<u8>> {
    use std::io::Write;

    use write::SnappyFramedEncoder;
    use test_helpers::*;

    // Build a large vector containing repeated text data.
    let hunk = try!(read_file("data/arbres.txt"));
    let data = repeat_data(&hunk, repeats);

    // Compress it.
    let mut compressed = vec!();
    {
        let mut compressor = try!(SnappyFramedEncoder::new(&mut compressed));
        let written = try!(compressor.write(&data));
        assert_eq!(data.len(), written);
        try!(compressor.flush());
    }
    Ok(compressed)
}

#[test]
fn decode_example_stream() {
    use std::fs::File;
    use dribble::DribbleReader;

    use test_helpers::*;

    let mut compressed = File::open("data/arbres.txt.sz").unwrap();
    let mut dribble = DribbleReader::new(&mut compressed);
    let mut decompressor = SnappyFramedDecoder::new(&mut dribble,
                                                    CrcMode::Verify);
    let mut decompressed = vec!();
    decompressor.read_to_end(&mut decompressed).unwrap();

    let expected = read_file("data/arbres.txt").unwrap();
    assert_eq!(expected, decompressed);
}

#[test]
fn encode_and_decode_large_data() {
    use std::io::Cursor;

    use test_helpers::*;

    // Build a multi-MB vector containing text data.
    let hunk = read_file("data/arbres.txt").unwrap();
    let input = repeat_data(&hunk, 1000);
    let compressed = large_compressed_data(1000).unwrap();

    // Decode it.
    let mut cursor = Cursor::new(&compressed as &[u8]);
    let mut decompressor = SnappyFramedDecoder::new(&mut cursor,
                                                    CrcMode::Verify);
    let mut decompressed = vec!();
    decompressor.read_to_end(&mut decompressed).unwrap();

    // Compare it.
    assert_eq!(input, decompressed);
}

// Test for invalid inputs:
//   - No identifier chunk.
//   - Incomplete chunks: All positions return errors.
//   - Reserved chunk types.
//   - Bad CRC.
//   - Overlong chunks (both compressed--two variants--and uncompressed).

#[cfg(all(test, feature = "unstable"))]
mod benches {
    use std::io::{Cursor, Read};
    use test::Bencher;

    use super::{CrcMode, SnappyFramedDecoder, large_compressed_data};

    #[bench]
    fn decompress_speed(b: &mut Bencher) {
        let data = large_compressed_data(250).unwrap();

        let mut output_bytes = 0;
        let mut buffer = vec![0; 128*1024];
        b.iter(|| {
            output_bytes = 0;
            {
                let mut cursor = Cursor::new(&data as &[u8]);
                let mut decoder = SnappyFramedDecoder::new(&mut cursor,
                                                           CrcMode::Ignore);
                // Avoid read_to_end here; it's too slow for large blocks
                // of data.
                loop {
                    let bytes_read = decoder.read(&mut buffer).unwrap();
                    output_bytes += bytes_read;
                    if bytes_read == 0 { break; }
                }
            }
            buffer[0]
        });
        b.bytes = output_bytes as u64;
    }
}
<|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/. */

//! Rust wrappers around the raw JS apis

use libc::types::os::arch::c95::{size_t, c_uint};
use libc::uintptr_t;
use libc::c_char;
use std::cmp;
use std::rc;
use std::rt::Runtime;
use std::string;
use jsapi::*;
use jsval::{JSVal, NullValue};
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use ERR;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = rc::Rc<rt_rsrc>;

pub struct rt_rsrc {
    pub ptr : *mut JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&mut self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *mut JSRuntime) -> rt {
    return rc::Rc::new(rt_rsrc {
        ptr: p
    })
}

pub trait RtUtils {
    fn cx(&self) -> rc::Rc<Cx>;
}

impl RtUtils for rc::Rc<rt_rsrc> {
    fn cx(&self) -> rc::Rc<Cx> {
        unsafe {
            new_context(JS_NewContext(self.deref().ptr,
                                      default_stacksize as size_t), self.clone())
        }
    }
}

/// If you set your own callback, the first step should be a call to this one.
pub unsafe extern fn gc_callback(rt: *mut JSRuntime, _status: JSGCStatus) {
    use std::rt::local::Local;
    use std::rt::task::Task;
    let mut task = Local::borrow(None::<Task>);
    let runtime = task.take_runtime();
    let (start, end) = runtime.stack_bounds();
    JS_SetNativeStackBounds(rt, cmp::min(start, end) as uintptr_t,
                            cmp::max(start, end) as uintptr_t);
    task.put_runtime(runtime);
}

pub fn rt() -> rt {
    unsafe {
        let runtime = JS_Init(default_heapsize);
        JS_SetGCCallback(runtime, Some(gc_callback));
        return new_runtime(runtime);
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    pub ptr: *mut JSContext,
    pub rt: rt,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn drop(&mut self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *mut JSContext, rt: rt) -> rc::Rc<Cx> {
    return rc::Rc::new(Cx {
        ptr: ptr,
        rt: rt,
    })
}

impl Cx {
    pub fn set_default_options_and_version(&self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    pub fn set_options(&self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    pub fn set_version(&self, v: JSVersion) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    pub fn set_logging_error_reporter(&self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportError));
        }
    }

    pub fn set_error_reporter(&self, reportfn: unsafe extern "C" fn(*mut JSContext, *const c_char, *mut JSErrorReport)) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportfn));
        }
    }

    pub fn evaluate_script(&self, glob: *mut JSObject, script: String, filename: String, line_num: uint)
                    -> Result<(),()> {
        let script_utf16: Vec<u16> = script.as_slice().utf16_units().collect();
        let filename_cstr = filename.to_c_str();
        let mut rval: JSVal = NullValue();
        debug!("Evaluating script from {:s} with content {}", filename, script);
        // SpiderMonkey does not approve of null pointers.
        let (ptr, len) = if script_utf16.len() == 0 {
            static empty: &'static [u16] = &[];
            (empty.as_ptr(), 0)
        } else {
            (script_utf16.as_ptr(), script_utf16.len() as c_uint)
        };
        assert!(ptr.is_not_null());
        unsafe {
            if ERR == JS_EvaluateUCScript(self.ptr, glob, ptr, len,
                                          filename_cstr.as_ptr(), line_num as c_uint,
                                          &mut rval) {
                debug!("...err!");
                Err(())
            } else {
                // we could return the script result but then we'd have
                // to root it and so forth and, really, who cares?
                debug!("...ok!");
                Ok(())
            }
        }
    }
}

pub unsafe extern fn reportError(_cx: *mut JSContext, msg: *const c_char, report: *mut JSErrorReport) {
    let fnptr = (*report).filename;
    let fname = if fnptr.is_not_null() {string::raw::from_buf(fnptr as *const i8 as *const u8)} else {"none".to_string()};
    let lineno = (*report).lineno;
    let msg = string::raw::from_buf(msg as *const i8 as *const u8);
    error!("Error at {:s}:{}: {:s}\n", fname, lineno, msg);
}

pub fn with_compartment<R>(cx: *mut JSContext, object: *mut JSObject, cb: || -> R) -> R {
    unsafe {
        let call = JS_EnterCrossCompartmentCall(cx, object);
        let result = cb();
        JS_LeaveCrossCompartmentCall(call);
        result
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::RtUtils;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.deref().set_default_options_and_version();
        cx.deref().set_logging_error_reporter();
    }

}
<commit_msg>Remove GC callback, it crashes with rust upgrade. jdm says it's not required.<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/. */

//! Rust wrappers around the raw JS apis

use libc::types::os::arch::c95::{size_t, c_uint};
use libc::uintptr_t;
use libc::c_char;
use std::cmp;
use std::rc;
use std::rt::Runtime;
use std::string;
use jsapi::*;
use jsval::{JSVal, NullValue};
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use ERR;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = rc::Rc<rt_rsrc>;

pub struct rt_rsrc {
    pub ptr : *mut JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&mut self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *mut JSRuntime) -> rt {
    return rc::Rc::new(rt_rsrc {
        ptr: p
    })
}

pub trait RtUtils {
    fn cx(&self) -> rc::Rc<Cx>;
}

impl RtUtils for rc::Rc<rt_rsrc> {
    fn cx(&self) -> rc::Rc<Cx> {
        unsafe {
            new_context(JS_NewContext(self.deref().ptr,
                                      default_stacksize as size_t), self.clone())
        }
    }
}

pub fn rt() -> rt {
    unsafe {
        let runtime = JS_Init(default_heapsize);
        return new_runtime(runtime);
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    pub ptr: *mut JSContext,
    pub rt: rt,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn drop(&mut self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *mut JSContext, rt: rt) -> rc::Rc<Cx> {
    return rc::Rc::new(Cx {
        ptr: ptr,
        rt: rt,
    })
}

impl Cx {
    pub fn set_default_options_and_version(&self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    pub fn set_options(&self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    pub fn set_version(&self, v: JSVersion) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    pub fn set_logging_error_reporter(&self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportError));
        }
    }

    pub fn set_error_reporter(&self, reportfn: unsafe extern "C" fn(*mut JSContext, *const c_char, *mut JSErrorReport)) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportfn));
        }
    }

    pub fn evaluate_script(&self, glob: *mut JSObject, script: String, filename: String, line_num: uint)
                    -> Result<(),()> {
        let script_utf16: Vec<u16> = script.as_slice().utf16_units().collect();
        let filename_cstr = filename.to_c_str();
        let mut rval: JSVal = NullValue();
        debug!("Evaluating script from {:s} with content {}", filename, script);
        // SpiderMonkey does not approve of null pointers.
        let (ptr, len) = if script_utf16.len() == 0 {
            static empty: &'static [u16] = &[];
            (empty.as_ptr(), 0)
        } else {
            (script_utf16.as_ptr(), script_utf16.len() as c_uint)
        };
        assert!(ptr.is_not_null());
        unsafe {
            if ERR == JS_EvaluateUCScript(self.ptr, glob, ptr, len,
                                          filename_cstr.as_ptr(), line_num as c_uint,
                                          &mut rval) {
                debug!("...err!");
                Err(())
            } else {
                // we could return the script result but then we'd have
                // to root it and so forth and, really, who cares?
                debug!("...ok!");
                Ok(())
            }
        }
    }
}

pub unsafe extern fn reportError(_cx: *mut JSContext, msg: *const c_char, report: *mut JSErrorReport) {
    let fnptr = (*report).filename;
    let fname = if fnptr.is_not_null() {string::raw::from_buf(fnptr as *const i8 as *const u8)} else {"none".to_string()};
    let lineno = (*report).lineno;
    let msg = string::raw::from_buf(msg as *const i8 as *const u8);
    error!("Error at {:s}:{}: {:s}\n", fname, lineno, msg);
}

pub fn with_compartment<R>(cx: *mut JSContext, object: *mut JSObject, cb: || -> R) -> R {
    unsafe {
        let call = JS_EnterCrossCompartmentCall(cx, object);
        let result = cb();
        JS_LeaveCrossCompartmentCall(call);
        result
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::RtUtils;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.deref().set_default_options_and_version();
        cx.deref().set_logging_error_reporter();
    }

}
<|endoftext|>