<commit_before>//! Low level and high level rdkafka producers.
//!
//! ## The C librdkafka producer
//! Rust-rdkafka relies on the C librdkafka producer to communicate with Kafka, so in order to understand how
//! the Rust producers work it is important to understand the basics of the C one as well.
//!
//! ### Async
//! The librdkafka producer is completely asynchronous: it maintains a memory buffer where messages
//! waiting to be sent or currently in flight are stored. Once a message is delivered or an error
//! occurred and the maximum number of retries has been reached, the producer will enqueue a delivery
//! event with the appropriate delivery result into an internal event queue.
//!
//! The librdkafka user is responsible for calling the `poll` function at regular intervals to
//! process those events; the thread calling `poll` will be the one executing the user-specified
//! delivery callback for every delivery event. If `poll` is not called, or not frequently
//! enough, the producer will return a `RDKafkaError::QueueFull` error and it won't be able to send any other
//! message until more delivery event are processed via `poll`. The `QueueFull` error can also be
//! returned if Kafka is not able to receive the messages quickly enough.
//!
//! ### Error reporting
//! The C library will try deal with all the transient errors such as broker disconnection,
//! timeouts etc. These errors, called global errors, are automatically logged in rust-rdkafka, but
//! they normally don't require any handling as they are automatically handled internally.
//! To see the logs, make sure you initialize the logger.
//!
//! As mentioned earlier, errors specific to message production will be reported in the delivery callback.
//!
//! ### Buffering
//! Buffering is done automatically by librdkafka. When `send` is called, the message is enqueued
//! internally and once enough messages have been enqueued, or when enough time has passed, they will be
//! sent to Kafka as a single batch. You can control the behavior of the buffer by configuring the
//! the `queue.buffering.max.*` parameters listed below.
//!
//! ## Rust-rdkafka producers
//! Rust-rdkafka (rdkafka for brevity) provides two sets of producers: low level and high level.
//!
//! ### Low level producers
//! The lowest level producer provided by rdkafka is called `BaseProducer`. The goal of the
//! `BaseProducer` is to be as close as possible to the C one while maintaining a safe Rust interface.
//! In particular, the `BaseProducer` needs to be polled at regular intervals to execute
//! any delivery callback that might be waiting and to make sure the queue doesn't fill up.
//!
//! Another low lever producer is the `ThreadedProducer`, which is a `BaseProducer` with
//! a dedicated thread for polling.
//!
//! The delivery callback can be defined using a `ProducerContext`. More information in the
//! `base_producer` module.
//!
//! ### High level producer
//! At the moment the only high level producer implemented is the `FutureProducer`. The
//! `FutureProducer` doesn't rely on user-defined callbacks to notify the delivery or failure of
//! a message; instead, this information will be returned in a Future. The `FutureProducer` also
//! uses an internal thread that is used for polling, which makes calling poll explicitly not necessary.
//! The returned future will contain information about the delivered message in case of success,
//! or a copy of the original message in case of failure. Additional computation can be chained
//! to the returned future, and it will executed by the future executor once the value is available
//! (for more information, check the documentation of the futures crate).
//!
//! ## Configuration
//!
//! ### Producer configuration
//!
//! For the configuration parameters common to both producers and consumers, refer to the
//! documentation in the `config` module. Here are listed the most commonly used producer
//! configuration. Click [here](https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md) for the full list.
//!
//! - `queue.buffering.max.messages` (100000): Maximum number of messages allowed on the producer queue.
//! - `queue.buffering.max.kbytes` (4000000): Maximum total message size sum allowed on the producer queue. This property has higher priority than queue.buffering.max.messages.
//! - `queue.buffering.max.ms` (0): Delay in milliseconds to wait for messages in the producer queue to accumulate before sending a request to the brokers. A higher value allows larger and more effective (less overhead, improved compression) batches of messages to accumulate at the expense of increased message delivery latency.
//! - `message.send.max.retries` (2): How many times to retry sending a failing batch. Note: retrying may cause reordering.
//! - `compression.codec` (none): Compression codec to use for compressing message sets.
//! - `request.required.acks` (1): This field indicates how many acknowledgements the leader broker must receive from ISR brokers before responding to the request: 0=Broker does not send any response/ack to client, 1=Only the leader broker will need to ack the message, -1 or all=broker will block until message is committed by all in sync replicas (ISRs) or broker's in.sync.replicas setting before sending response.
//! - `request.timeout.ms` (5000): The ack timeout of the producer request in milliseconds. This value is only enforced by the broker and relies on request.required.acks being != 0.
//! - `message.timeout.ms` (300000): Local message timeout. This value is only enforced locally and limits the time a produced message waits for successful delivery. A time of 0 is infinite.
//! - `produce.offset.report` (false): Report offset of produced message back to application.
//!

pub mod base_producer;
pub mod future_producer;

pub use self::base_producer::{
    BaseProducer,
    DeliveryResult,
    DefaultProducerContext,
    ProducerContext,
    ThreadedProducer
};
pub use self::future_producer::FutureProducer;
<commit_msg>Reexport DeliveryFuture from the producer module<commit_after>//! Low level and high level rdkafka producers.
//!
//! ## The C librdkafka producer
//! Rust-rdkafka relies on the C librdkafka producer to communicate with Kafka, so in order to understand how
//! the Rust producers work it is important to understand the basics of the C one as well.
//!
//! ### Async
//! The librdkafka producer is completely asynchronous: it maintains a memory buffer where messages
//! waiting to be sent or currently in flight are stored. Once a message is delivered or an error
//! occurred and the maximum number of retries has been reached, the producer will enqueue a delivery
//! event with the appropriate delivery result into an internal event queue.
//!
//! The librdkafka user is responsible for calling the `poll` function at regular intervals to
//! process those events; the thread calling `poll` will be the one executing the user-specified
//! delivery callback for every delivery event. If `poll` is not called, or not frequently
//! enough, the producer will return a `RDKafkaError::QueueFull` error and it won't be able to send any other
//! message until more delivery event are processed via `poll`. The `QueueFull` error can also be
//! returned if Kafka is not able to receive the messages quickly enough.
//!
//! ### Error reporting
//! The C library will try deal with all the transient errors such as broker disconnection,
//! timeouts etc. These errors, called global errors, are automatically logged in rust-rdkafka, but
//! they normally don't require any handling as they are automatically handled internally.
//! To see the logs, make sure you initialize the logger.
//!
//! As mentioned earlier, errors specific to message production will be reported in the delivery callback.
//!
//! ### Buffering
//! Buffering is done automatically by librdkafka. When `send` is called, the message is enqueued
//! internally and once enough messages have been enqueued, or when enough time has passed, they will be
//! sent to Kafka as a single batch. You can control the behavior of the buffer by configuring the
//! the `queue.buffering.max.*` parameters listed below.
//!
//! ## Rust-rdkafka producers
//! Rust-rdkafka (rdkafka for brevity) provides two sets of producers: low level and high level.
//!
//! ### Low level producers
//! The lowest level producer provided by rdkafka is called `BaseProducer`. The goal of the
//! `BaseProducer` is to be as close as possible to the C one while maintaining a safe Rust interface.
//! In particular, the `BaseProducer` needs to be polled at regular intervals to execute
//! any delivery callback that might be waiting and to make sure the queue doesn't fill up.
//!
//! Another low lever producer is the `ThreadedProducer`, which is a `BaseProducer` with
//! a dedicated thread for polling.
//!
//! The delivery callback can be defined using a `ProducerContext`. More information in the
//! `base_producer` module.
//!
//! ### High level producer
//! At the moment the only high level producer implemented is the `FutureProducer`. The
//! `FutureProducer` doesn't rely on user-defined callbacks to notify the delivery or failure of
//! a message; instead, this information will be returned in a Future. The `FutureProducer` also
//! uses an internal thread that is used for polling, which makes calling poll explicitly not necessary.
//! The returned future will contain information about the delivered message in case of success,
//! or a copy of the original message in case of failure. Additional computation can be chained
//! to the returned future, and it will executed by the future executor once the value is available
//! (for more information, check the documentation of the futures crate).
//!
//! ## Configuration
//!
//! ### Producer configuration
//!
//! For the configuration parameters common to both producers and consumers, refer to the
//! documentation in the `config` module. Here are listed the most commonly used producer
//! configuration. Click [here](https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md) for the full list.
//!
//! - `queue.buffering.max.messages` (100000): Maximum number of messages allowed on the producer queue.
//! - `queue.buffering.max.kbytes` (4000000): Maximum total message size sum allowed on the producer queue. This property has higher priority than queue.buffering.max.messages.
//! - `queue.buffering.max.ms` (0): Delay in milliseconds to wait for messages in the producer queue to accumulate before sending a request to the brokers. A higher value allows larger and more effective (less overhead, improved compression) batches of messages to accumulate at the expense of increased message delivery latency.
//! - `message.send.max.retries` (2): How many times to retry sending a failing batch. Note: retrying may cause reordering.
//! - `compression.codec` (none): Compression codec to use for compressing message sets.
//! - `request.required.acks` (1): This field indicates how many acknowledgements the leader broker must receive from ISR brokers before responding to the request: 0=Broker does not send any response/ack to client, 1=Only the leader broker will need to ack the message, -1 or all=broker will block until message is committed by all in sync replicas (ISRs) or broker's in.sync.replicas setting before sending response.
//! - `request.timeout.ms` (5000): The ack timeout of the producer request in milliseconds. This value is only enforced by the broker and relies on request.required.acks being != 0.
//! - `message.timeout.ms` (300000): Local message timeout. This value is only enforced locally and limits the time a produced message waits for successful delivery. A time of 0 is infinite.
//! - `produce.offset.report` (false): Report offset of produced message back to application.
//!

pub mod base_producer;
pub mod future_producer;

pub use self::base_producer::{
    BaseProducer,
    DeliveryResult,
    DefaultProducerContext,
    ProducerContext,
    ThreadedProducer
};
pub use self::future_producer::{
    FutureProducer,
    DeliveryFuture
};
<|endoftext|>


<commit_before>#![allow(dead_code)]
extern crate byteorder;

use std::net::TcpStream;
use std::io;
use std::io::{Write, Read};
use std::convert;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};

/// Serializes types into a buffer
macro_rules! serialize_type {
    ($dst:expr, $name:expr, u16) => {
        $dst.write_u16::<BigEndian>($name).unwrap();
    };
    ($dst:expr, $name:expr, i64) => {
        $dst.write_i64::<BigEndian>($name).unwrap();
    };
    ($dst:expr, $name:expr, VarInt) => {
        try!(write_varint($dst, $name));
    };
    ($dst:expr, $name:expr, String) => {
        try!(write_varint($dst, $name.len() as i32));
        $dst.extend($name.bytes());
    };
    ($dst:expr, $name:expr, Empty) => {

    };
    ($dst:expr, $name:expr, $ftype:ident) => {
        unimplemented!()
    };
}

/// Deserializes types from a buffer
macro_rules! deserialize_type {
    ($src:expr, String) => {
        {
            let len = read_variant(&mut $src).unwrap();
            let mut ret = String::new();
            (&mut $src).take(len as u64).read_to_string(&mut ret).unwrap();
            ret
        }
    };
    ($src:expr, i64) => {
        $src.read_i64::<BigEndian>().unwrap()
    };
    ($src:expr, Empty) => { Empty };
    ($src:expr, $ftype:ident) => {
        unimplemented!()
    };
}

/// Helper macro for defining packets
#[macro_export]
macro_rules! state_packets {
     ($($state:ident $stateName:ident {
        $($dir:ident $dirName:ident {
            $($name:ident => $id:expr {
                $($field:ident: $field_type:ident),+
            }),*
        })+
    })+) => {
        use protocol::*;
        use std::io;
        use std::io::{Read, Write};
        use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};

        pub enum Packet {
        $(
            $(
                $(
        $name($state::$dir::$name),
                )*
            )+
        )+
        }

        $(
        pub mod $state {
            $(
            pub mod $dir {
                use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
                use protocol::*;
                use std::io;
                use std::io::{Read, Write};

                $(
                    pub struct $name {
                        $(pub $field: $field_type),+,
                    }

                    impl PacketType for $name {

                        fn packet_id(&self) -> i32{ $id }

                        fn write(self, buf: &mut Vec<u8>) -> Result<(), io::Error> {
                            $(
                                serialize_type!(buf, self.$field, $field_type);
                            )+

                            Result::Ok(())
                        }
                    }
                )*
            }
            )+
        }
        )+

        /// Returns the packet for the given state, direction and id after parsing the fields
        /// from the buffer.
        pub fn packet_by_id(state: State, dir: Direction, id: i32, mut buf: &mut io::Cursor<Vec<u8>>) -> Option<Packet> {
            match state {
                $(
                    State::$stateName => {
                        match dir {
                            $(
                                Direction::$dirName => {
                                    match id {
                                    $(
                                        $id => Option::Some(Packet::$name($state::$dir::$name {
                                            $($field: deserialize_type!(buf, $field_type)),+,
                                        })),
                                    )*
                                        _ => Option::None
                                    }
                                }
                            )+
                        }
                    }
                )+
            }
        }
    }
}

pub mod packet;

/// VarInt have a variable size (between 1 and 5 bytes) when encoded based
/// on the size of the number
pub type VarInt = i32;

/// Encodes a VarInt into the Writer
pub fn write_varint(buf: &mut io::Write, v: VarInt) -> Result<(), io::Error> {
    const PART : u32 = 0x7F;
    let mut val = v as u32;
    loop {
        if (val & !PART) == 0 {
            try!(buf.write_u8(val as u8));
            return Result::Ok(());
        }
        try!(buf.write_u8(((val & PART) | 0x80) as u8));
        val >>= 7;
    }
}

/// Decodes a VarInt from the Reader
pub fn read_variant(buf: &mut io::Read) -> Result<VarInt, io::Error> {
    const PART : u32 = 0x7F;
    let mut size = 0;
    let mut val = 0u32;
    loop {
        let b = try!(buf.read_u8()) as u32;
        val |= (b & PART) << (size * 7);
        size+=1;
        if size > 5 {
            return Result::Err(io::Error::new(io::ErrorKind::InvalidInput, Error::Err("VarInt too big".to_string())))
        }
        if (b & 0x80) == 0 {
            break
        }
    }

    Result::Ok(val as VarInt)
}

/// Direction is used to define whether packets are going to the
/// server or the client.
pub enum Direction {
    Serverbound,
    Clientbound
}

/// The protocol has multiple 'sub-protocols' or states which control which
/// packet an id points to.
#[derive(Clone, Copy)]
pub enum State {
    Handshaking,
    Play,
    Status,
    Login
}

/// Return for any protocol related error.
#[derive(Debug)]
pub enum Error {
    Err(String),
    IOError(io::Error),
}

impl convert::From<io::Error> for Error {
    fn from(e : io::Error) -> Error {
        Error::IOError(e)
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::Err(ref val) => &val[..],
            &Error::IOError(ref e) => e.description(),
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f : &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match self {
            &Error::Err(ref val) => write!(f, "protocol error: {}", val),
            &Error::IOError(ref e) => e.fmt(f)
        }
    }
}

/// Helper for empty structs
pub struct Empty;

pub struct Conn {
    stream: TcpStream,
    host: String,
    port: u16,
    direction: Direction,
    state: State,
}

impl Conn {
    pub fn new(target: &str) -> Result<Conn, Error>{
        // TODO SRV record support
        let stream = match TcpStream::connect(target) {
            Ok(val) => val,
            Err(err) => return Result::Err(Error::IOError(err))
        };
        let parts = target.split(":").collect::<Vec<&str>>();
        Result::Ok(Conn {
            stream: stream,
            host: parts[0].to_owned(),
            port: parts[1].parse().unwrap(),
            direction: Direction::Serverbound,
            state: State::Handshaking,
        })
    }

    // TODO: compression and encryption

    pub fn write_packet<T: PacketType>(&mut self, packet: T) -> Result<(), Error> {
        let mut buf = Vec::new();
        try!(write_varint(&mut buf, packet.packet_id()));
        try!(packet.write(&mut buf));
        try!(write_varint(&mut self.stream, buf.len() as i32));
        try!(self.stream.write_all(&buf.into_boxed_slice()));

        Result::Ok(())
    }

    pub fn read_packet(&mut self) -> Result<packet::Packet, Error> {
        let len = try!(read_variant(&mut self.stream)) as usize;
        let mut ibuf = Vec::with_capacity(len);
        try!((&mut self.stream).take(len as u64).read_to_end(&mut ibuf));

        let mut buf = io::Cursor::new(ibuf);
        let id = try!(read_variant(&mut buf));

        let dir = match self.direction {
            Direction::Clientbound => Direction::Serverbound,
            Direction::Serverbound => Direction::Clientbound,
        };

        let packet = packet::packet_by_id(self.state, dir, id, &mut buf);

        match packet {
            Some(val) => {
                let pos = buf.position() as usize;
                let ibuf = buf.into_inner();
                if ibuf.len() < pos {
                    return Result::Err(Error::Err(format!("Failed to read all of packet 0x{:X}, had {} bytes left", id, ibuf.len() - pos)))
                }
                Result::Ok(val)
            },
            None => Result::Err(Error::Err("missing packet".to_string()))
        }
    }
}

pub trait PacketType {
    fn packet_id(&self) -> i32;

    fn write(self, buf: &mut Vec<u8>) -> Result<(), io::Error>;
}

#[test]
fn test() {
    return; // Skip
    let mut c = Conn::new("localhost:25565").unwrap();

    c.write_packet(packet::handshake::serverbound::Handshake{
        protocol_version: 69,
        host: "localhost".to_string(),
        port: 25565,
        next: 1,
    }).unwrap();
    c.state = State::Status;
    c.write_packet(packet::status::serverbound::StatusRequest{empty: Empty}).unwrap();

    match c.read_packet().unwrap() {
        packet::Packet::StatusResponse(val) => println!("{}", val.status),
        _ => panic!("Wrong packet"),
    }

    c.write_packet(packet::status::serverbound::StatusPing{ping: 4433}).unwrap();

    match c.read_packet().unwrap() {
        packet::Packet::StatusPong(val) => println!("{}", val.ping),
        _ => panic!("Wrong packet"),
    }

    panic!("TODO!");
}
<commit_msg>Clean up protocol encoding/decoding<commit_after>#![allow(dead_code)]
extern crate byteorder;

use std::default;
use std::net::TcpStream;
use std::io;
use std::io::{Write, Read};
use std::convert;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};

/// Helper macro for defining packets
#[macro_export]
macro_rules! state_packets {
     ($($state:ident $stateName:ident {
        $($dir:ident $dirName:ident {
            $($name:ident => $id:expr {
                $($field:ident: $field_type:ident),+
            }),*
        })+
    })+) => {
        use protocol::*;
        use std::io;
        use protocol::{Serializable};

        pub enum Packet {
        $(
            $(
                $(
        $name($state::$dir::$name),
                )*
            )+
        )+
        }

        $(
        pub mod $state {
            $(
            pub mod $dir {
                use protocol::*;
                use std::io;
                use protocol::{Serializable};

                $(
                    #[derive(Default)]
                    pub struct $name {
                        $(pub $field: $field_type),+,
                    }

                    impl PacketType for $name {

                        fn packet_id(&self) -> i32{ $id }

                        fn write(self, buf: &mut Vec<u8>) -> Result<(), io::Error> {
                            $(
                                try!(self.$field.write_to(buf));
                            )+

                            Result::Ok(())
                        }
                    }
                )*
            }
            )+
        }
        )+

        /// Returns the packet for the given state, direction and id after parsing the fields
        /// from the buffer.
        pub fn packet_by_id(state: State, dir: Direction, id: i32, mut buf: &mut io::Cursor<Vec<u8>>) -> Result<Option<Packet>, io::Error> {
            match state {
                $(
                    State::$stateName => {
                        match dir {
                            $(
                                Direction::$dirName => {
                                    match id {
                                    $(
                                        $id => {
                                            let mut packet : $state::$dir::$name = $state::$dir::$name::default();
                                            $(
                                                packet.$field = try!($field_type::read_from(&mut buf));
                                            )+
                                            Result::Ok(Option::Some(Packet::$name(packet)))
                                        },
                                    )*
                                        _ => Result::Ok(Option::None)
                                    }
                                }
                            )+
                        }
                    }
                )+
            }
        }
    }
}

pub mod packet;

trait Serializable {
    fn read_from(buf: &mut io::Read) -> Result<Self, io::Error>;
    fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error>;
}

impl Serializable for String {
    fn read_from(buf: &mut io::Read) -> Result<String, io::Error> {
        let len = try!(VarInt::read_from(buf)).0;
        let mut ret = String::new();
        try!(buf.take(len as u64).read_to_string(&mut ret));
        Result::Ok(ret)
    }
    fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
        let bytes = self.as_bytes();
        try!(VarInt(bytes.len() as i32).write_to(buf));
        try!(buf.write_all(bytes));
        Result::Ok(())
    }
}

impl Serializable for Empty {
    fn read_from(buf: &mut io::Read) -> Result<Empty, io::Error> {
        Result::Ok(Empty)
    }
    fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
        Result::Ok(())
    }
}

impl Default for Empty {
    fn default() -> Empty { Empty }
}

impl Serializable for i32 {
    fn read_from(buf: &mut io::Read) -> Result<i32, io::Error> {
        Result::Ok(try!(buf.read_i32::<BigEndian>()))
    }
    fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
        try!(buf.write_i32::<BigEndian>(*self));
        Result::Ok(())
    }
}

impl Serializable for i64 {
    fn read_from(buf: &mut io::Read) -> Result<i64, io::Error> {
        Result::Ok(try!(buf.read_i64::<BigEndian>()))
    }
    fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
        try!(buf.write_i64::<BigEndian>(*self));
        Result::Ok(())
    }
}

impl Serializable for u16 {
    fn read_from(buf: &mut io::Read) -> Result<u16, io::Error> {
        Result::Ok(try!(buf.read_u16::<BigEndian>()))
    }
    fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
        try!(buf.write_u16::<BigEndian>(*self));
        Result::Ok(())
    }
}

/// VarInt have a variable size (between 1 and 5 bytes) when encoded based
/// on the size of the number
pub struct VarInt(i32);

impl Serializable for VarInt {
    /// Decodes a VarInt from the Reader
    fn read_from(buf: &mut io::Read) -> Result<VarInt, io::Error> {
        const PART : u32 = 0x7F;
        let mut size = 0;
        let mut val = 0u32;
        loop {
            let b = try!(buf.read_u8()) as u32;
            val |= (b & PART) << (size * 7);
            size+=1;
            if size > 5 {
                return Result::Err(io::Error::new(io::ErrorKind::InvalidInput, Error::Err("VarInt too big".to_string())))
            }
            if (b & 0x80) == 0 {
                break
            }
        }

        Result::Ok(VarInt(val as i32))
    }

    /// Encodes a VarInt into the Writer
    fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
        const PART : u32 = 0x7F;
        let mut val = self.0 as u32;
        loop {
            if (val & !PART) == 0 {
                try!(buf.write_u8(val as u8));
                return Result::Ok(());
            }
            try!(buf.write_u8(((val & PART) | 0x80) as u8));
            val >>= 7;
        }
    }
}

impl default::Default for VarInt {
    fn default() -> VarInt { VarInt(0) }
}

/// Direction is used to define whether packets are going to the
/// server or the client.
pub enum Direction {
    Serverbound,
    Clientbound
}

/// The protocol has multiple 'sub-protocols' or states which control which
/// packet an id points to.
#[derive(Clone, Copy)]
pub enum State {
    Handshaking,
    Play,
    Status,
    Login
}

/// Return for any protocol related error.
#[derive(Debug)]
pub enum Error {
    Err(String),
    IOError(io::Error),
}

impl convert::From<io::Error> for Error {
    fn from(e : io::Error) -> Error {
        Error::IOError(e)
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::Err(ref val) => &val[..],
            &Error::IOError(ref e) => e.description(),
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f : &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match self {
            &Error::Err(ref val) => write!(f, "protocol error: {}", val),
            &Error::IOError(ref e) => e.fmt(f)
        }
    }
}

/// Helper for empty structs
pub struct Empty;

pub struct Conn {
    stream: TcpStream,
    host: String,
    port: u16,
    direction: Direction,
    state: State,
}

impl Conn {
    pub fn new(target: &str) -> Result<Conn, Error>{
        // TODO SRV record support
        let stream = match TcpStream::connect(target) {
            Ok(val) => val,
            Err(err) => return Result::Err(Error::IOError(err))
        };
        let parts = target.split(":").collect::<Vec<&str>>();
        Result::Ok(Conn {
            stream: stream,
            host: parts[0].to_owned(),
            port: parts[1].parse().unwrap(),
            direction: Direction::Serverbound,
            state: State::Handshaking,
        })
    }

    // TODO: compression and encryption

    pub fn write_packet<T: PacketType>(&mut self, packet: T) -> Result<(), Error> {
        let mut buf = Vec::new();
        try!(VarInt(packet.packet_id()).write_to(&mut buf));
        try!(packet.write(&mut buf));
        try!(VarInt(buf.len() as i32).write_to(&mut self.stream));
        try!(self.stream.write_all(&buf.into_boxed_slice()));

        Result::Ok(())
    }

    pub fn read_packet(&mut self) -> Result<packet::Packet, Error> {
        let len = try!(VarInt::read_from(&mut self.stream)).0 as usize;
        let mut ibuf = Vec::with_capacity(len);
        try!((&mut self.stream).take(len as u64).read_to_end(&mut ibuf));

        let mut buf = io::Cursor::new(ibuf);
        let id = try!(VarInt::read_from(&mut buf)).0;

        let dir = match self.direction {
            Direction::Clientbound => Direction::Serverbound,
            Direction::Serverbound => Direction::Clientbound,
        };

        let packet = try!(packet::packet_by_id(self.state, dir, id, &mut buf));

        match packet {
            Some(val) => {
                let pos = buf.position() as usize;
                let ibuf = buf.into_inner();
                if ibuf.len() < pos {
                    return Result::Err(Error::Err(format!("Failed to read all of packet 0x{:X}, had {} bytes left", id, ibuf.len() - pos)))
                }
                Result::Ok(val)
            },
            None => Result::Err(Error::Err("missing packet".to_string()))
        }
    }
}

pub trait PacketType {
    fn packet_id(&self) -> i32;

    fn write(self, buf: &mut Vec<u8>) -> Result<(), io::Error>;
}

#[test]
fn test() {
    let mut c = Conn::new("localhost:25565").unwrap();

    c.write_packet(packet::handshake::serverbound::Handshake{
        protocol_version: VarInt(69),
        host: "localhost".to_string(),
        port: 25565,
        next: VarInt(1),
    }).unwrap();
    c.state = State::Status;
    c.write_packet(packet::status::serverbound::StatusRequest{empty: Empty}).unwrap();

    match c.read_packet().unwrap() {
        packet::Packet::StatusResponse(val) => println!("{}", val.status),
        _ => panic!("Wrong packet"),
    }

    c.write_packet(packet::status::serverbound::StatusPing{ping: 4433}).unwrap();

    match c.read_packet().unwrap() {
        packet::Packet::StatusPong(val) => println!("{}", val.ping),
        _ => panic!("Wrong packet"),
    }

    panic!("TODO!");
}
<|endoftext|>


<commit_before>#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
use crate::convert::Convert;
#[cfg(feature = "specialize")]
use crate::BuildHasherExt;

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))]
pub use crate::aes_hash::*;

#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri))))]
pub use crate::fallback_hash::*;

#[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
use const_random::const_random;
use core::fmt;
use core::hash::BuildHasher;
#[cfg(feature = "specialize")]
use core::hash::Hash;
use core::hash::Hasher;

#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std as alloc;

#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
use alloc::boxed::Box;
use core::sync::atomic::{AtomicUsize, Ordering};
#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
use once_cell::race::OnceBox;

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))]
use crate::aes_hash::*;
#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri))))]
use crate::fallback_hash::*;

#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
static SEEDS: OnceBox<[[u64; 4]; 2]> = OnceBox::new();

static COUNTER: AtomicUsize = AtomicUsize::new(0);

pub(crate) const PI: [u64; 4] = [
    0x243f_6a88_85a3_08d3,
    0x1319_8a2e_0370_7344,
    0xa409_3822_299f_31d0,
    0x082e_fa98_ec4e_6c89,
];

#[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
const PI2: [u64; 4] = [
    0x4528_21e6_38d0_1377,
    0xbe54_66cf_34e9_0c6c,
    0xc0ac_29b7_c97c_50dd,
    0x3f84_d5b5_b547_0917,
];

#[inline]
pub(crate) fn seeds() -> [u64; 4] {
    #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
    {
        SEEDS.get_or_init(|| {
            let mut result: [u8; 64] = [0; 64];
            getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.");
            Box::new(result.convert())
        })[1]
    }
    #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
    {
        [
            const_random!(u64),
            const_random!(u64),
            const_random!(u64),
            const_random!(u64),
        ]
    }
    #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
    {
        PI
    }
}

/// Provides a [Hasher] factory. This is typically used (e.g. by [HashMap]) to create
/// [AHasher]s in order to hash the keys of the map. See `build_hasher` below.
///
/// [build_hasher]: ahash::
/// [Hasher]: std::hash::Hasher
/// [BuildHasher]: std::hash::BuildHasher
/// [HashMap]: std::collections::HashMap
#[derive(Clone)]
pub struct RandomState {
    pub(crate) k0: u64,
    pub(crate) k1: u64,
    pub(crate) k2: u64,
    pub(crate) k3: u64,
}

impl fmt::Debug for RandomState {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("RandomState { .. }")
    }
}

impl RandomState {
    /// Use randomly generated keys
    #[inline]
    pub fn new() -> RandomState {
        #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
        {
            let seeds = SEEDS.get_or_init(|| {
                let mut result: [u8; 64] = [0; 64];
                getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.");
                Box::new(result.convert())
            });
            RandomState::from_keys(seeds[0], seeds[1])
        }
        #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
        {
            RandomState::from_keys(
                [
                    const_random!(u64),
                    const_random!(u64),
                    const_random!(u64),
                    const_random!(u64),
                ],
                [
                    const_random!(u64),
                    const_random!(u64),
                    const_random!(u64),
                    const_random!(u64),
                ],
            )
        }
        #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
        {
            RandomState::from_keys(PI, PI2)
        }
    }

    /// Allows for supplying seeds, but each time it is called the resulting state will be different.
    /// This is done using a static counter, so it can safely be used with a fixed keys.
    #[inline]
    pub fn generate_with(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
        RandomState::from_keys(seeds(), [k0, k1, k2, k3])
    }

    fn from_keys(a: [u64; 4], b: [u64; 4]) -> RandomState {
        let [k0, k1, k2, k3] = a;
        let mut hasher = AHasher::from_random_state(&RandomState { k0, k1, k2, k3 });

        let stack_mem_loc = &hasher as *const _ as usize;
        #[cfg(not(all(target_arch = "arm", target_os = "none")))]
        {
            hasher.write_usize(COUNTER.fetch_add(stack_mem_loc, Ordering::Relaxed));
        }
        #[cfg(all(target_arch = "arm", target_os = "none"))]
        {
            let previous = COUNTER.load(Ordering::Relaxed);
            let new = previous.wrapping_add(stack_mem_loc);
            COUNTER.store(new, Ordering::Relaxed);
            hasher.write_usize(new);
        }
        #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
        hasher.write_usize(&PI as *const _ as usize);
        let mix = |k: u64| {
            let mut h = hasher.clone();
            h.write_u64(k);
            h.finish()
        };

        RandomState {
            k0: mix(b[0]),
            k1: mix(b[1]),
            k2: mix(b[2]),
            k3: mix(b[3]),
        }
    }

    /// Internal. Used by Default.
    #[inline]
    pub(crate) fn with_fixed_keys() -> RandomState {
        let [k0, k1, k2, k3] = seeds();
        RandomState { k0, k1, k2, k3 }
    }

    /// Allows for explicitly setting the seeds to used.
    #[inline]
    pub const fn with_seeds(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
        RandomState { k0, k1, k2, k3 }
    }
}

impl Default for RandomState {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl BuildHasher for RandomState {
    type Hasher = AHasher;

    /// Constructs a new [AHasher] with keys based on this [RandomState] object.
    /// This means that two different [RandomState]s will will generate
    /// [AHasher]s that will return different hashcodes, but [Hasher]s created from the same [BuildHasher]
    /// will generate the same hashes for the same input data.
    ///
    /// # Examples
    ///
    /// ```
    /// use ahash::{AHasher, RandomState};
    /// use std::hash::{Hasher, BuildHasher};
    ///
    /// let build_hasher = RandomState::new();
    /// let mut hasher_1 = build_hasher.build_hasher();
    /// let mut hasher_2 = build_hasher.build_hasher();
    ///
    /// hasher_1.write_u32(1234);
    /// hasher_2.write_u32(1234);
    ///
    /// assert_eq!(hasher_1.finish(), hasher_2.finish());
    ///
    /// let other_build_hasher = RandomState::new();
    /// let mut different_hasher = other_build_hasher.build_hasher();
    /// different_hasher.write_u32(1234);
    /// assert_ne!(different_hasher.finish(), hasher_1.finish());
    /// ```
    /// [Hasher]: std::hash::Hasher
    /// [BuildHasher]: std::hash::BuildHasher
    /// [HashMap]: std::collections::HashMap
    #[inline]
    fn build_hasher(&self) -> AHasher {
        AHasher::from_random_state(self)
    }
}

#[cfg(feature = "specialize")]
impl BuildHasherExt for RandomState {
    #[inline]
    fn hash_as_u64<T: Hash + ?Sized>(&self, value: &T) -> u64 {
        let mut hasher = AHasherU64 {
            buffer: self.k0,
            pad: self.k1,
        };
        value.hash(&mut hasher);
        hasher.finish()
    }

    #[inline]
    fn hash_as_fixed_length<T: Hash + ?Sized>(&self, value: &T) -> u64 {
        let mut hasher = AHasherFixed(self.build_hasher());
        value.hash(&mut hasher);
        hasher.finish()
    }

    #[inline]
    fn hash_as_str<T: Hash + ?Sized>(&self, value: &T) -> u64 {
        let mut hasher = AHasherStr(self.build_hasher());
        value.hash(&mut hasher);
        hasher.finish()
    }
}

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

    #[test]
    fn test_unique() {
        let a = RandomState::new();
        let b = RandomState::new();
        assert_ne!(a.build_hasher().finish(), b.build_hasher().finish());
    }

    #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
    #[test]
    fn test_not_pi() {
        assert_ne!(PI, seeds());
    }

    #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
    #[test]
    fn test_not_pi_const() {
        assert_ne!(PI, seeds());
    }

    #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
    #[test]
    fn test_pi() {
        assert_eq!(PI, seeds());
    }

    #[test]
    fn test_with_seeds_const() {
        const _CONST_RANDOM_STATE: RandomState = RandomState::with_seeds(17, 19, 21, 23);
    }
}
<commit_msg>Apply pi xor to RandomState.with_seeds also.<commit_after>#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
use crate::convert::Convert;
#[cfg(feature = "specialize")]
use crate::BuildHasherExt;

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))]
pub use crate::aes_hash::*;

#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri))))]
pub use crate::fallback_hash::*;

#[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
use const_random::const_random;
use core::fmt;
use core::hash::BuildHasher;
#[cfg(feature = "specialize")]
use core::hash::Hash;
use core::hash::Hasher;

#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std as alloc;

#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
use alloc::boxed::Box;
use core::sync::atomic::{AtomicUsize, Ordering};
#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
use once_cell::race::OnceBox;

#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)))]
use crate::aes_hash::*;
#[cfg(not(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri))))]
use crate::fallback_hash::*;

#[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
static SEEDS: OnceBox<[[u64; 4]; 2]> = OnceBox::new();

static COUNTER: AtomicUsize = AtomicUsize::new(0);

pub(crate) const PI: [u64; 4] = [
    0x243f_6a88_85a3_08d3,
    0x1319_8a2e_0370_7344,
    0xa409_3822_299f_31d0,
    0x082e_fa98_ec4e_6c89,
];

pub(crate) const PI2: [u64; 4] = [
    0x4528_21e6_38d0_1377,
    0xbe54_66cf_34e9_0c6c,
    0xc0ac_29b7_c97c_50dd,
    0x3f84_d5b5_b547_0917,
];

#[inline]
pub(crate) fn seeds() -> [u64; 4] {
    #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
    {
        SEEDS.get_or_init(|| {
            let mut result: [u8; 64] = [0; 64];
            getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.");
            Box::new(result.convert())
        })[1]
    }
    #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
    {
        [
            const_random!(u64),
            const_random!(u64),
            const_random!(u64),
            const_random!(u64),
        ]
    }
    #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
    {
        PI
    }
}

/// Provides a [Hasher] factory. This is typically used (e.g. by [HashMap]) to create
/// [AHasher]s in order to hash the keys of the map. See `build_hasher` below.
///
/// [build_hasher]: ahash::
/// [Hasher]: std::hash::Hasher
/// [BuildHasher]: std::hash::BuildHasher
/// [HashMap]: std::collections::HashMap
#[derive(Clone)]
pub struct RandomState {
    pub(crate) k0: u64,
    pub(crate) k1: u64,
    pub(crate) k2: u64,
    pub(crate) k3: u64,
}

impl fmt::Debug for RandomState {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("RandomState { .. }")
    }
}

impl RandomState {
    /// Use randomly generated keys
    #[inline]
    pub fn new() -> RandomState {
        #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
        {
            let seeds = SEEDS.get_or_init(|| {
                let mut result: [u8; 64] = [0; 64];
                getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.");
                Box::new(result.convert())
            });
            RandomState::from_keys(seeds[0], seeds[1])
        }
        #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
        {
            RandomState::from_keys(
                [
                    const_random!(u64),
                    const_random!(u64),
                    const_random!(u64),
                    const_random!(u64),
                ],
                [
                    const_random!(u64),
                    const_random!(u64),
                    const_random!(u64),
                    const_random!(u64),
                ],
            )
        }
        #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
        {
            RandomState::from_keys(PI, PI2)
        }
    }

    /// Allows for supplying seeds, but each time it is called the resulting state will be different.
    /// This is done using a static counter, so it can safely be used with a fixed keys.
    #[inline]
    pub fn generate_with(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
        RandomState::from_keys(seeds(), [k0, k1, k2, k3])
    }

    fn from_keys(a: [u64; 4], b: [u64; 4]) -> RandomState {
        let [k0, k1, k2, k3] = a;
        let mut hasher = AHasher::from_random_state(&RandomState { k0, k1, k2, k3 });

        let stack_mem_loc = &hasher as *const _ as usize;
        #[cfg(not(all(target_arch = "arm", target_os = "none")))]
        {
            hasher.write_usize(COUNTER.fetch_add(stack_mem_loc, Ordering::Relaxed));
        }
        #[cfg(all(target_arch = "arm", target_os = "none"))]
        {
            let previous = COUNTER.load(Ordering::Relaxed);
            let new = previous.wrapping_add(stack_mem_loc);
            COUNTER.store(new, Ordering::Relaxed);
            hasher.write_usize(new);
        }
        #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
        hasher.write_usize(&PI as *const _ as usize);
        let mix = |k: u64| {
            let mut h = hasher.clone();
            h.write_u64(k);
            h.finish()
        };

        RandomState {
            k0: mix(b[0]),
            k1: mix(b[1]),
            k2: mix(b[2]),
            k3: mix(b[3]),
        }
    }

    /// Internal. Used by Default.
    #[inline]
    pub(crate) fn with_fixed_keys() -> RandomState {
        let [k0, k1, k2, k3] = seeds();
        RandomState { k0, k1, k2, k3 }
    }

    /// Allows for explicitly setting the seeds to used.
    #[inline]
    pub const fn with_seeds(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
        RandomState { k0: k0 ^ PI2[0], k1: k1 ^ PI2[1], k2: k2 ^ PI2[2], k3: k3 ^ PI2[3] }
    }
}

impl Default for RandomState {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl BuildHasher for RandomState {
    type Hasher = AHasher;

    /// Constructs a new [AHasher] with keys based on this [RandomState] object.
    /// This means that two different [RandomState]s will will generate
    /// [AHasher]s that will return different hashcodes, but [Hasher]s created from the same [BuildHasher]
    /// will generate the same hashes for the same input data.
    ///
    /// # Examples
    ///
    /// ```
    /// use ahash::{AHasher, RandomState};
    /// use std::hash::{Hasher, BuildHasher};
    ///
    /// let build_hasher = RandomState::new();
    /// let mut hasher_1 = build_hasher.build_hasher();
    /// let mut hasher_2 = build_hasher.build_hasher();
    ///
    /// hasher_1.write_u32(1234);
    /// hasher_2.write_u32(1234);
    ///
    /// assert_eq!(hasher_1.finish(), hasher_2.finish());
    ///
    /// let other_build_hasher = RandomState::new();
    /// let mut different_hasher = other_build_hasher.build_hasher();
    /// different_hasher.write_u32(1234);
    /// assert_ne!(different_hasher.finish(), hasher_1.finish());
    /// ```
    /// [Hasher]: std::hash::Hasher
    /// [BuildHasher]: std::hash::BuildHasher
    /// [HashMap]: std::collections::HashMap
    #[inline]
    fn build_hasher(&self) -> AHasher {
        AHasher::from_random_state(self)
    }
}

#[cfg(feature = "specialize")]
impl BuildHasherExt for RandomState {
    #[inline]
    fn hash_as_u64<T: Hash + ?Sized>(&self, value: &T) -> u64 {
        let mut hasher = AHasherU64 {
            buffer: self.k0,
            pad: self.k1,
        };
        value.hash(&mut hasher);
        hasher.finish()
    }

    #[inline]
    fn hash_as_fixed_length<T: Hash + ?Sized>(&self, value: &T) -> u64 {
        let mut hasher = AHasherFixed(self.build_hasher());
        value.hash(&mut hasher);
        hasher.finish()
    }

    #[inline]
    fn hash_as_str<T: Hash + ?Sized>(&self, value: &T) -> u64 {
        let mut hasher = AHasherStr(self.build_hasher());
        value.hash(&mut hasher);
        hasher.finish()
    }
}

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

    #[test]
    fn test_unique() {
        let a = RandomState::new();
        let b = RandomState::new();
        assert_ne!(a.build_hasher().finish(), b.build_hasher().finish());
    }

    #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
    #[test]
    fn test_not_pi() {
        assert_ne!(PI, seeds());
    }

    #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
    #[test]
    fn test_not_pi_const() {
        assert_ne!(PI, seeds());
    }

    #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
    #[test]
    fn test_pi() {
        assert_eq!(PI, seeds());
    }

    #[test]
    fn test_with_seeds_const() {
        const _CONST_RANDOM_STATE: RandomState = RandomState::with_seeds(17, 19, 21, 23);
    }
}
<|endoftext|>


<commit_before>use super::{Null, Value, ValueRef};
use ::Result;

pub enum ToSqlOutput<'a> {
    Borrowed(ValueRef<'a>),
    Owned(Value),

    #[cfg(feature = "blob")]
    ZeroBlob(i32),
}

impl<'a, T: ?Sized> From<&'a T> for ToSqlOutput<'a> where &'a T: Into<ValueRef<'a>> {
    fn from(t: &'a T) -> Self {
        ToSqlOutput::Borrowed(t.into())
    }
}

impl<'a, T: Into<Value>> From<T> for ToSqlOutput<'a> {
    fn from(t: T) -> Self {
        ToSqlOutput::Owned(t.into())
    }
}

/// A trait for types that can be converted into SQLite values.
pub trait ToSql {
    fn to_sql(&self) -> Result<ToSqlOutput>;
}

// We should be able to use a generic impl like this:
//
// impl<T: Copy> ToSql for T where T: Into<Value> {
//     fn to_sql(&self) -> Result<ToSqlOutput> {
//         Ok(ToSqlOutput::from((*self).into()))
//     }
// }
//
// instead of the following macro, but this runs afoul of
// https://github.com/rust-lang/rust/issues/30191 and reports conflicting
// implementations even when there aren't any.

macro_rules! to_sql_self(
    ($t:ty) => (
        impl ToSql for $t {
            fn to_sql(&self) -> Result<ToSqlOutput> {
                Ok(ToSqlOutput::from(*self))
            }
        }
    )
);

to_sql_self!(Null);
to_sql_self!(bool);
to_sql_self!(i32);
to_sql_self!(i64);
to_sql_self!(f64);

impl<'a, T: ?Sized> ToSql for &'a T where &'a T: Into<ToSqlOutput<'a>> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from((*self).into()))
    }
}

impl ToSql for String {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self.as_str()))
    }
}

impl ToSql for Vec<u8> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self.as_slice()))
    }
}

impl ToSql for Value {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self))
    }
}

impl<T: ToSql> ToSql for Option<T> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        match *self {
            None => Ok(ToSqlOutput::from(Null)),
            Some(ref t) => t.to_sql(),
        }
    }
}
<commit_msg>Add doc comments to ToSqlOutput.<commit_after>use super::{Null, Value, ValueRef};
use ::Result;

/// ToSqlOutput represents the possible output types for implementors of the ToSql trait.
pub enum ToSqlOutput<'a> {
    /// A borrowed SQLite-representable value.
    Borrowed(ValueRef<'a>),

    /// An owned SQLite-representable value.
    Owned(Value),

    /// A BLOB of the given length that is filled with zeroes.
    #[cfg(feature = "blob")]
    ZeroBlob(i32),
}

impl<'a, T: ?Sized> From<&'a T> for ToSqlOutput<'a> where &'a T: Into<ValueRef<'a>> {
    fn from(t: &'a T) -> Self {
        ToSqlOutput::Borrowed(t.into())
    }
}

impl<'a, T: Into<Value>> From<T> for ToSqlOutput<'a> {
    fn from(t: T) -> Self {
        ToSqlOutput::Owned(t.into())
    }
}

/// A trait for types that can be converted into SQLite values.
pub trait ToSql {
    fn to_sql(&self) -> Result<ToSqlOutput>;
}

// We should be able to use a generic impl like this:
//
// impl<T: Copy> ToSql for T where T: Into<Value> {
//     fn to_sql(&self) -> Result<ToSqlOutput> {
//         Ok(ToSqlOutput::from((*self).into()))
//     }
// }
//
// instead of the following macro, but this runs afoul of
// https://github.com/rust-lang/rust/issues/30191 and reports conflicting
// implementations even when there aren't any.

macro_rules! to_sql_self(
    ($t:ty) => (
        impl ToSql for $t {
            fn to_sql(&self) -> Result<ToSqlOutput> {
                Ok(ToSqlOutput::from(*self))
            }
        }
    )
);

to_sql_self!(Null);
to_sql_self!(bool);
to_sql_self!(i32);
to_sql_self!(i64);
to_sql_self!(f64);

impl<'a, T: ?Sized> ToSql for &'a T where &'a T: Into<ToSqlOutput<'a>> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from((*self).into()))
    }
}

impl ToSql for String {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self.as_str()))
    }
}

impl ToSql for Vec<u8> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self.as_slice()))
    }
}

impl ToSql for Value {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        Ok(ToSqlOutput::from(self))
    }
}

impl<T: ToSql> ToSql for Option<T> {
    fn to_sql(&self) -> Result<ToSqlOutput> {
        match *self {
            None => Ok(ToSqlOutput::from(Null)),
            Some(ref t) => t.to_sql(),
        }
    }
}
<|endoftext|>


<commit_before>use byteorder;
use prelude::*;

impl From<u128> for Uuid {
    fn from(f: u128) -> Self {
        let mut uuid = Uuid::default();

        {
            use byteorder::ByteOrder;

            byteorder::NativeEndian::write_u128(&mut uuid.bytes.as_mut(), f);
        }

        uuid
    }
}

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

    #[test]
    fn test_from_u128() {
        const U128: u128 = 0x3a0724b4_93a0_4d87_ac28_759c6caa13c4;

        let uuid = Uuid::from(U128);

        let uuid2: Uuid = U128.into();

        assert_eq!(uuid, uuid2)
    }

}<commit_msg>add `Uuid::from_u128` constructor<commit_after>use byteorder;
use prelude::*;

impl Uuid {
    /// Creates a new [`Uuid`] from a `u128` value.
    ///
    /// To create a [`Uuid`] from `u128`s, you need `u128` feature enabled for this crate.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    #[inline(always)]
    pub fn from_u128(quad: u128) -> Self {
        Uuid::from(quad)
    }
}

impl From<u128> for Uuid {
    fn from(f: u128) -> Self {
        let mut uuid = Uuid::default();

        {
            use byteorder::ByteOrder;

            byteorder::NativeEndian::write_u128(&mut uuid.bytes.as_mut(), f);
        }

        uuid
    }
}

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

    #[test]
    fn test_from_u128() {
        const U128: u128 = 0x3a0724b4_93a0_4d87_ac28_759c6caa13c4;

        let uuid = Uuid::from(U128);

        let uuid2: Uuid = U128.into();

        assert_eq!(uuid, uuid2)
    }

}<|endoftext|>


<commit_before>use std::iter;
use std::fmt::Display;
use std::iter::Iterator;

use unicode_width::UnicodeWidthStr;

use buffer::Buffer;
use widgets::{Block, Widget};
use layout::Rect;
use style::Style;

pub enum Item<'i, D: 'i> {
    Data(D),
    StyledData(D, &'i Style),
}

pub struct List<'b, 'i, L, D: 'i>
where
    L: Iterator<Item = Item<'i, D>>,
{
    block: Option<Block<'b>>,
    items: L,
    style: Style,
}

impl<'b, 'i, L, D> Default for List<'b, 'i, L, D>
where
    L: Iterator<Item = Item<'i, D>> + Default,
{
    fn default() -> List<'b, 'i, L, D> {
        List {
            block: None,
            items: L::default(),
            style: Default::default(),
        }
    }
}

impl<'b, 'i, L, D> List<'b, 'i, L, D>
where
    L: Iterator<Item = Item<'i, D>>,
{
    pub fn new(items: L) -> List<'b, 'i, L, D> {
        List {
            block: None,
            items: items,
            style: Default::default(),
        }
    }

    pub fn block(&'b mut self, block: Block<'b>) -> &mut List<'b, 'i, L, D> {
        self.block = Some(block);
        self
    }

    pub fn items<I>(&'b mut self, items: I) -> &mut List<'b, 'i, L, D>
    where
        I: IntoIterator<Item = Item<'i, D>, IntoIter = L>,
    {
        self.items = items.into_iter();
        self
    }

    pub fn style(&'b mut self, style: Style) -> &mut List<'b, 'i, L, D> {
        self.style = style;
        self
    }
}

impl<'b, 'i, L, D> Widget for List<'b, 'i, L, D>
where
    L: Iterator<Item = Item<'i, D>>,
    D: Display,
{
    fn draw(&mut self, area: &Rect, buf: &mut Buffer) {
        let list_area = match self.block {
            Some(ref mut b) => {
                b.draw(area, buf);
                b.inner(area)
            }
            None => *area,
        };

        if list_area.width < 1 || list_area.height < 1 {
            return;
        }

        self.background(&list_area, buf, self.style.bg);

        for (i, item) in self.items
            .by_ref()
            .enumerate()
            .take(list_area.height as usize)
        {
            match item {
                Item::Data(ref v) => {
                    buf.set_stringn(
                        list_area.left(),
                        list_area.top() + i as u16,
                        &format!("{}", v),
                        list_area.width as usize,
                        &Style::default(),
                    );
                }
                Item::StyledData(ref v, s) => {
                    buf.set_stringn(
                        list_area.left(),
                        list_area.top() + i as u16,
                        &format!("{}", v),
                        list_area.width as usize,
                        s,
                    );
                }
            };
        }
    }
}

/// A widget to display several items among which one can be selected (optional)
///
/// # Examples
///
/// ```
/// # extern crate tui;
/// # use tui::widgets::{Block, Borders, SelectableList};
/// # use tui::style::{Style, Color, Modifier};
/// # fn main() {
/// SelectableList::default()
///     .block(Block::default().title("SelectableList").borders(Borders::ALL))
///     .items(&["Item 1", "Item 2", "Item 3"])
///     .select(1)
///     .style(Style::default().fg(Color::White))
///     .highlight_style(Style::default().modifier(Modifier::Italic))
///     .highlight_symbol(">>");
/// # }
/// ```
pub struct SelectableList<'b> {
    block: Option<Block<'b>>,
    /// Items to be displayed
    items: Vec<&'b str>,
    /// Index of the one selected
    selected: Option<usize>,
    /// Base style of the widget
    style: Style,
    /// Style used to render selected item
    highlight_style: Style,
    /// Symbol in front of the selected item (Shift all items to the right)
    highlight_symbol: Option<&'b str>,
}

impl<'b> Default for SelectableList<'b> {
    fn default() -> SelectableList<'b> {
        SelectableList {
            block: None,
            items: Vec::new(),
            selected: None,
            style: Default::default(),
            highlight_style: Default::default(),
            highlight_symbol: None,
        }
    }
}

impl<'b> SelectableList<'b> {
    pub fn block(&'b mut self, block: Block<'b>) -> &mut SelectableList<'b> {
        self.block = Some(block);
        self
    }

    pub fn items<I>(&'b mut self, items: &'b [I]) -> &mut SelectableList<'b>
    where
        I: AsRef<str> + 'b,
    {
        self.items = items.iter().map(|i| i.as_ref()).collect::<Vec<&str>>();
        self
    }

    pub fn style(&'b mut self, style: Style) -> &mut SelectableList<'b> {
        self.style = style;
        self
    }

    pub fn highlight_symbol(&'b mut self, highlight_symbol: &'b str) -> &mut SelectableList<'b> {
        self.highlight_symbol = Some(highlight_symbol);
        self
    }

    pub fn highlight_style(&'b mut self, highlight_style: Style) -> &mut SelectableList<'b> {
        self.highlight_style = highlight_style;
        self
    }

    pub fn select(&'b mut self, index: usize) -> &'b mut SelectableList<'b> {
        self.selected = Some(index);
        self
    }
}

impl<'b> Widget for SelectableList<'b> {
    fn draw(&mut self, area: &Rect, buf: &mut Buffer) {
        let list_area = match self.block {
            Some(ref mut b) => b.inner(area),
            None => *area,
        };

        let list_height = list_area.height as usize;

        // Use highlight_style only if something is selected
        let (selected, highlight_style) = match self.selected {
            Some(i) => (i, &self.highlight_style),
            None => (0, &self.style),
        };
        let highlight_symbol = self.highlight_symbol.unwrap_or("");
        let blank_symbol = iter::repeat(" ")
            .take(highlight_symbol.width())
            .collect::<String>();
        // Make sure the list show the selected item
        let offset = if selected >= list_height {
            selected - list_height + 1
        } else {
            0
        };

        // Render items
        let items = self.items
            .iter()
            .enumerate()
            .map(|(i, item)| {
                if i == selected {
                    Item::StyledData(format!("{} {}", highlight_symbol, item), highlight_style)
                } else {
                    Item::StyledData(format!("{} {}", blank_symbol, item), &self.style)
                }
            })
            .skip(offset as usize);
        List::new(items)
            .block(self.block.unwrap_or_default())
            .draw(area, buf);
    }
}
<commit_msg>[widgets][list] Set the style of the underlying list<commit_after>use std::iter;
use std::fmt::Display;
use std::iter::Iterator;

use unicode_width::UnicodeWidthStr;

use buffer::Buffer;
use widgets::{Block, Widget};
use layout::Rect;
use style::Style;

pub enum Item<'i, D: 'i> {
    Data(D),
    StyledData(D, &'i Style),
}

pub struct List<'b, 'i, L, D: 'i>
where
    L: Iterator<Item = Item<'i, D>>,
{
    block: Option<Block<'b>>,
    items: L,
    style: Style,
}

impl<'b, 'i, L, D> Default for List<'b, 'i, L, D>
where
    L: Iterator<Item = Item<'i, D>> + Default,
{
    fn default() -> List<'b, 'i, L, D> {
        List {
            block: None,
            items: L::default(),
            style: Default::default(),
        }
    }
}

impl<'b, 'i, L, D> List<'b, 'i, L, D>
where
    L: Iterator<Item = Item<'i, D>>,
{
    pub fn new(items: L) -> List<'b, 'i, L, D> {
        List {
            block: None,
            items: items,
            style: Default::default(),
        }
    }

    pub fn block(&'b mut self, block: Block<'b>) -> &mut List<'b, 'i, L, D> {
        self.block = Some(block);
        self
    }

    pub fn items<I>(&'b mut self, items: I) -> &mut List<'b, 'i, L, D>
    where
        I: IntoIterator<Item = Item<'i, D>, IntoIter = L>,
    {
        self.items = items.into_iter();
        self
    }

    pub fn style(&'b mut self, style: Style) -> &mut List<'b, 'i, L, D> {
        self.style = style;
        self
    }
}

impl<'b, 'i, L, D> Widget for List<'b, 'i, L, D>
where
    L: Iterator<Item = Item<'i, D>>,
    D: Display,
{
    fn draw(&mut self, area: &Rect, buf: &mut Buffer) {
        let list_area = match self.block {
            Some(ref mut b) => {
                b.draw(area, buf);
                b.inner(area)
            }
            None => *area,
        };

        if list_area.width < 1 || list_area.height < 1 {
            return;
        }

        self.background(&list_area, buf, self.style.bg);

        for (i, item) in self.items
            .by_ref()
            .enumerate()
            .take(list_area.height as usize)
        {
            match item {
                Item::Data(ref v) => {
                    buf.set_stringn(
                        list_area.left(),
                        list_area.top() + i as u16,
                        &format!("{}", v),
                        list_area.width as usize,
                        &Style::default(),
                    );
                }
                Item::StyledData(ref v, s) => {
                    buf.set_stringn(
                        list_area.left(),
                        list_area.top() + i as u16,
                        &format!("{}", v),
                        list_area.width as usize,
                        s,
                    );
                }
            };
        }
    }
}

/// A widget to display several items among which one can be selected (optional)
///
/// # Examples
///
/// ```
/// # extern crate tui;
/// # use tui::widgets::{Block, Borders, SelectableList};
/// # use tui::style::{Style, Color, Modifier};
/// # fn main() {
/// SelectableList::default()
///     .block(Block::default().title("SelectableList").borders(Borders::ALL))
///     .items(&["Item 1", "Item 2", "Item 3"])
///     .select(1)
///     .style(Style::default().fg(Color::White))
///     .highlight_style(Style::default().modifier(Modifier::Italic))
///     .highlight_symbol(">>");
/// # }
/// ```
pub struct SelectableList<'b> {
    block: Option<Block<'b>>,
    /// Items to be displayed
    items: Vec<&'b str>,
    /// Index of the one selected
    selected: Option<usize>,
    /// Base style of the widget
    style: Style,
    /// Style used to render selected item
    highlight_style: Style,
    /// Symbol in front of the selected item (Shift all items to the right)
    highlight_symbol: Option<&'b str>,
}

impl<'b> Default for SelectableList<'b> {
    fn default() -> SelectableList<'b> {
        SelectableList {
            block: None,
            items: Vec::new(),
            selected: None,
            style: Default::default(),
            highlight_style: Default::default(),
            highlight_symbol: None,
        }
    }
}

impl<'b> SelectableList<'b> {
    pub fn block(&'b mut self, block: Block<'b>) -> &mut SelectableList<'b> {
        self.block = Some(block);
        self
    }

    pub fn items<I>(&'b mut self, items: &'b [I]) -> &mut SelectableList<'b>
    where
        I: AsRef<str> + 'b,
    {
        self.items = items.iter().map(|i| i.as_ref()).collect::<Vec<&str>>();
        self
    }

    pub fn style(&'b mut self, style: Style) -> &mut SelectableList<'b> {
        self.style = style;
        self
    }

    pub fn highlight_symbol(&'b mut self, highlight_symbol: &'b str) -> &mut SelectableList<'b> {
        self.highlight_symbol = Some(highlight_symbol);
        self
    }

    pub fn highlight_style(&'b mut self, highlight_style: Style) -> &mut SelectableList<'b> {
        self.highlight_style = highlight_style;
        self
    }

    pub fn select(&'b mut self, index: usize) -> &'b mut SelectableList<'b> {
        self.selected = Some(index);
        self
    }
}

impl<'b> Widget for SelectableList<'b> {
    fn draw(&mut self, area: &Rect, buf: &mut Buffer) {
        let list_area = match self.block {
            Some(ref mut b) => b.inner(area),
            None => *area,
        };

        let list_height = list_area.height as usize;

        // Use highlight_style only if something is selected
        let (selected, highlight_style) = match self.selected {
            Some(i) => (i, &self.highlight_style),
            None => (0, &self.style),
        };
        let highlight_symbol = self.highlight_symbol.unwrap_or("");
        let blank_symbol = iter::repeat(" ")
            .take(highlight_symbol.width())
            .collect::<String>();
        // Make sure the list show the selected item
        let offset = if selected >= list_height {
            selected - list_height + 1
        } else {
            0
        };

        // Render items
        let items = self.items
            .iter()
            .enumerate()
            .map(|(i, item)| {
                if i == selected {
                    Item::StyledData(format!("{} {}", highlight_symbol, item), highlight_style)
                } else {
                    Item::StyledData(format!("{} {}", blank_symbol, item), &self.style)
                }
            })
            .skip(offset as usize);
        List::new(items)
            .block(self.block.unwrap_or_default())
            .style(self.style)
            .draw(area, buf);
    }
}
<|endoftext|>


<commit_before>use ffi;
use parser::YamlErrorType;

use std::ptr;
use std::cast;
use std::c_vec::CVec;
use std::c_str::CString;
use libc;

pub struct YamlBaseEmitter {
    emitter_mem: ffi::yaml_emitter_t
}

impl YamlBaseEmitter {
    fn new() -> YamlBaseEmitter {
        YamlBaseEmitter {
            emitter_mem: ffi::yaml_emitter_t::new()
        }
    }
}

impl Drop for YamlBaseEmitter {
    fn drop(&mut self) {
        unsafe {
            ffi::yaml_emitter_delete(&mut self.emitter_mem);
        }
    }
}

pub struct YamlEmitter<'r> {
    base_emitter: YamlBaseEmitter,
    writer: &'r mut Writer
}

impl<'r> YamlEmitter<'r> {
    pub fn init<'r>(writer: &'r mut Writer) -> ~YamlEmitter<'r> {
        let mut emitter = ~YamlEmitter {
            base_emitter: YamlBaseEmitter::new(),
            writer: writer
        };

        unsafe {
            if ffi::yaml_emitter_initialize(&mut emitter.base_emitter.emitter_mem) == 0 {
                fail!("failed to initialize yaml_emitter_t");
            }

            ffi::yaml_emitter_set_output(&mut emitter.base_emitter.emitter_mem, handle_writer_cb, cast::transmute(&mut *emitter));
        }

        emitter
    }

    pub fn get_error(&self) -> (YamlErrorType, ~str) {
        let emitter_mem = &self.base_emitter.emitter_mem;
        unsafe {
            (YamlErrorType::conv(emitter_mem.error), CString::new(emitter_mem.problem, false).as_str().unwrap().to_owned())
        }
    }

    pub fn emit_stream_start_event(&mut self, encoding: ffi::YamlEncoding) -> Result<(), (YamlErrorType, ~str)> {
        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_stream_start_event_initialize(&mut event, encoding) == 0 {
                fail!("yaml_stream_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_stream_end_event(&mut self) -> Result<(), (YamlErrorType, ~str)> {
        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_stream_end_event_initialize(&mut event) == 0 {
                fail!("yaml_stream_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_document_start_event(&mut self,
            version_directive: Option<(int, int)>,
            tag_directives: &[(~str, ~str)],
            implicit: bool)
        -> Result<(), (YamlErrorType, ~str)>
    {
        let mut event = ffi::yaml_event_t::new();
        let mut vsn_dir = ffi::yaml_version_directive_t { major: 0, minor: 0 };
        let c_vsn_dir = match version_directive {
            Some((major, minor)) => {
                vsn_dir.major = major as libc::c_int;
                vsn_dir.minor = minor as libc::c_int;
                &vsn_dir as *ffi::yaml_version_directive_t
            },
            None => ptr::null()
        };

        let c_strs: ~[(CString, CString)] = tag_directives.iter().map(|tuple| {
            (tuple.ref0().to_c_str(), tuple.ref1().to_c_str())
        }).collect();
        let c_tag_dirs: ~[ffi::yaml_tag_directive_t] = c_strs.iter().map(|tuple| {
            ffi::yaml_tag_directive_t {
                handle: tuple.ref0().with_ref(|ptr| {ptr}),
                prefix: tuple.ref1().with_ref(|ptr| {ptr}),
            }
        }).collect();
        let tag_dir_start = c_tag_dirs.as_ptr();
        unsafe {
            let tag_dir_end = tag_dir_start.offset(c_tag_dirs.len() as int);
            let c_implicit = if implicit { 1 } else { 0 };

            if ffi::yaml_document_start_event_initialize(&mut event, c_vsn_dir, tag_dir_start, tag_dir_end, c_implicit) == 0 {
                fail!("yaml_document_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_document_end_event(&mut self, implicit: bool) -> Result<(), (YamlErrorType, ~str)> {
        let mut event = ffi::yaml_event_t::new();
        let c_implicit = if implicit { 1 } else { 0 };
        unsafe {
            if ffi::yaml_document_end_event_initialize(&mut event, c_implicit) == 0 {
                fail!("yaml_stream_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_alias_event(&mut self, anchor: &str) -> Result<(), (YamlErrorType, ~str)> {
        let mut event = ffi::yaml_event_t::new();
        let c_anchor = anchor.to_c_str();

        unsafe {
            c_anchor.with_ref(|ptr| {
                if ffi::yaml_alias_event_initialize(&mut event, ptr as *ffi::yaml_char_t) != 0 {
                    fail!("yaml_stream_end_event_initialize failed!")
                }
            });

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_scalar_event(&mut self, anchor: Option<&str>, tag: Option<&str>,
        value: &str, plain_implicit: bool, quoted_implicit: bool,
        style: ffi::YamlScalarStyle) -> Result<(), (YamlErrorType, ~str)>
    {
        let c_anchor = anchor.map(|s| { s.to_c_str() });
        let anchor_ptr = match c_anchor {
            Some(s) => s.with_ref(|ptr| { ptr }),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| { s.to_c_str() });
        let tag_ptr = match c_tag {
            Some(s) => s.with_ref(|ptr| { ptr }),
            None => ptr::null()
        };
        let c_plain_implicit = if plain_implicit { 1 } else { 0 };
        let c_quoted_implicit = if quoted_implicit { 1 } else { 0 };

        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_scalar_event_initialize(&mut event,
                    anchor_ptr as *ffi::yaml_char_t, tag_ptr as *ffi::yaml_char_t,
                    value.as_ptr(), value.len() as libc::c_int,
                    c_plain_implicit, c_quoted_implicit,
                    style) == 0
            {
                fail!("yaml_scalar_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_sequence_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
        style: ffi::YamlSequenceStyle) -> Result<(), (YamlErrorType, ~str)>
    {
        let c_anchor = anchor.map(|s| { s.to_c_str() });
        let anchor_ptr = match c_anchor {
            Some(s) => s.with_ref(|ptr| { ptr }),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| { s.to_c_str() });
        let tag_ptr = match c_tag {
            Some(s) => s.with_ref(|ptr| { ptr }),
            None => ptr::null()
        };
        let c_implicit = if implicit { 1 } else { 0 };

        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_sequence_start_event_initialize(&mut event,
                    anchor_ptr as *ffi::yaml_char_t, tag_ptr as *ffi::yaml_char_t,
                    c_implicit, style) == 0
            {
                fail!("yaml_sequence_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_sequence_end_event(&mut self) -> Result<(), (YamlErrorType, ~str)> {
        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_sequence_end_event_initialize(&mut event) == 0 {
                fail!("yaml_sequence_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_mapping_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
        style: ffi::YamlSequenceStyle) -> Result<(), (YamlErrorType, ~str)>
    {
        let c_anchor = anchor.map(|s| { s.to_c_str() });
        let anchor_ptr = match c_anchor {
            Some(s) => s.with_ref(|ptr| { ptr }),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| { s.to_c_str() });
        let tag_ptr = match c_tag {
            Some(s) => s.with_ref(|ptr| { ptr }),
            None => ptr::null()
        };
        let c_implicit = if implicit { 1 } else { 0 };

        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_mapping_start_event_initialize(&mut event,
                    anchor_ptr as *ffi::yaml_char_t, tag_ptr as *ffi::yaml_char_t,
                    c_implicit, style) == 0
            {
                fail!("yaml_mapping_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_mapping_end_event(&mut self) -> Result<(), (YamlErrorType, ~str)> {
        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_mapping_end_event_initialize(&mut event) == 0 {
                fail!("yaml_mapping_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn flush(&mut self) -> Result<(), (YamlErrorType, ~str)> {
        unsafe {
            if ffi::yaml_emitter_flush(&mut self.base_emitter.emitter_mem) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }
}

extern fn handle_writer_cb(data: *mut YamlEmitter, buffer: *u8, size: libc::size_t) -> libc::c_int {
    unsafe {
        let buf = CVec::new(buffer as *mut u8, size as uint);
        let emitter = &mut *data;
        match emitter.writer.write(buf.as_slice()) {
            Ok(()) => 1,
            Err(_) => 0
        }
    }
}

#[cfg(test)]
mod test {
    use std::io::MemWriter;
    use emitter::YamlEmitter;
    use ffi::{YamlUtf8Encoding, YamlPlainScalarStyle, YamlFlowSequenceStyle};

    #[test]
    #[allow(unused_must_use)]
    fn event_emitter_sequence_test() {
        let mut writer = MemWriter::new();
        {
            let mut emitter = YamlEmitter::init(&mut writer);
            emitter.emit_stream_start_event(YamlUtf8Encoding);
            emitter.emit_document_start_event(None, [], true);
            emitter.emit_sequence_start_event(None, None, true, YamlFlowSequenceStyle);
            emitter.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle);
            emitter.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle);
            emitter.emit_sequence_end_event();
            emitter.emit_document_end_event(false);
            emitter.emit_stream_end_event();
            emitter.flush();
        }
        assert_eq!(writer.get_ref(), "[1, 2]\n...\n".as_bytes());
    }

    #[test]
    #[allow(unused_must_use)]
    fn event_emitter_mapping_test() {
        let mut writer = MemWriter::new();
        {
            let mut emitter = YamlEmitter::init(&mut writer);
            emitter.emit_stream_start_event(YamlUtf8Encoding);
            emitter.emit_document_start_event(None, [], true);
            emitter.emit_mapping_start_event(None, None, true, YamlFlowSequenceStyle);
            emitter.emit_scalar_event(None, None, "a", true, false, YamlPlainScalarStyle);
            emitter.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle);
            emitter.emit_scalar_event(None, None, "b", true, false, YamlPlainScalarStyle);
            emitter.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle);
            emitter.emit_mapping_end_event();
            emitter.emit_document_end_event(false);
            emitter.emit_stream_end_event();
            emitter.flush();
        }
        assert_eq!(writer.get_ref(), "{a: 1, b: 2}\n...\n".as_bytes());
    }
}
<commit_msg>Use YamlVersionDirective instead of (int, int)<commit_after>use ffi;
use parser::YamlErrorType;
use event::YamlVersionDirective;

use std::ptr;
use std::cast;
use std::c_vec::CVec;
use std::c_str::CString;
use libc;

pub struct YamlBaseEmitter {
    emitter_mem: ffi::yaml_emitter_t
}

impl YamlBaseEmitter {
    fn new() -> YamlBaseEmitter {
        YamlBaseEmitter {
            emitter_mem: ffi::yaml_emitter_t::new()
        }
    }
}

impl Drop for YamlBaseEmitter {
    fn drop(&mut self) {
        unsafe {
            ffi::yaml_emitter_delete(&mut self.emitter_mem);
        }
    }
}

pub struct YamlEmitter<'r> {
    base_emitter: YamlBaseEmitter,
    writer: &'r mut Writer
}

impl<'r> YamlEmitter<'r> {
    pub fn init<'r>(writer: &'r mut Writer) -> ~YamlEmitter<'r> {
        let mut emitter = ~YamlEmitter {
            base_emitter: YamlBaseEmitter::new(),
            writer: writer
        };

        unsafe {
            if ffi::yaml_emitter_initialize(&mut emitter.base_emitter.emitter_mem) == 0 {
                fail!("failed to initialize yaml_emitter_t");
            }

            ffi::yaml_emitter_set_output(&mut emitter.base_emitter.emitter_mem, handle_writer_cb, cast::transmute(&mut *emitter));
        }

        emitter
    }

    pub fn get_error(&self) -> (YamlErrorType, ~str) {
        let emitter_mem = &self.base_emitter.emitter_mem;
        unsafe {
            (YamlErrorType::conv(emitter_mem.error), CString::new(emitter_mem.problem, false).as_str().unwrap().to_owned())
        }
    }

    pub fn emit_stream_start_event(&mut self, encoding: ffi::YamlEncoding) -> Result<(), (YamlErrorType, ~str)> {
        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_stream_start_event_initialize(&mut event, encoding) == 0 {
                fail!("yaml_stream_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_stream_end_event(&mut self) -> Result<(), (YamlErrorType, ~str)> {
        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_stream_end_event_initialize(&mut event) == 0 {
                fail!("yaml_stream_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_document_start_event(&mut self,
            version_directive: Option<YamlVersionDirective>,
            tag_directives: &[(~str, ~str)],
            implicit: bool)
        -> Result<(), (YamlErrorType, ~str)>
    {
        let mut event = ffi::yaml_event_t::new();
        let mut vsn_dir = ffi::yaml_version_directive_t { major: 0, minor: 0 };
        let c_vsn_dir = match version_directive {
            Some(directive) => {
                vsn_dir.major = directive.major as libc::c_int;
                vsn_dir.minor = directive.minor as libc::c_int;
                &vsn_dir as *ffi::yaml_version_directive_t
            },
            None => ptr::null()
        };

        let c_strs: ~[(CString, CString)] = tag_directives.iter().map(|tuple| {
            (tuple.ref0().to_c_str(), tuple.ref1().to_c_str())
        }).collect();
        let c_tag_dirs: ~[ffi::yaml_tag_directive_t] = c_strs.iter().map(|tuple| {
            ffi::yaml_tag_directive_t {
                handle: tuple.ref0().with_ref(|ptr| {ptr}),
                prefix: tuple.ref1().with_ref(|ptr| {ptr}),
            }
        }).collect();
        let tag_dir_start = c_tag_dirs.as_ptr();
        unsafe {
            let tag_dir_end = tag_dir_start.offset(c_tag_dirs.len() as int);
            let c_implicit = if implicit { 1 } else { 0 };

            if ffi::yaml_document_start_event_initialize(&mut event, c_vsn_dir, tag_dir_start, tag_dir_end, c_implicit) == 0 {
                fail!("yaml_document_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_document_end_event(&mut self, implicit: bool) -> Result<(), (YamlErrorType, ~str)> {
        let mut event = ffi::yaml_event_t::new();
        let c_implicit = if implicit { 1 } else { 0 };
        unsafe {
            if ffi::yaml_document_end_event_initialize(&mut event, c_implicit) == 0 {
                fail!("yaml_stream_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_alias_event(&mut self, anchor: &str) -> Result<(), (YamlErrorType, ~str)> {
        let mut event = ffi::yaml_event_t::new();
        let c_anchor = anchor.to_c_str();

        unsafe {
            c_anchor.with_ref(|ptr| {
                if ffi::yaml_alias_event_initialize(&mut event, ptr as *ffi::yaml_char_t) != 0 {
                    fail!("yaml_stream_end_event_initialize failed!")
                }
            });

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_scalar_event(&mut self, anchor: Option<&str>, tag: Option<&str>,
        value: &str, plain_implicit: bool, quoted_implicit: bool,
        style: ffi::YamlScalarStyle) -> Result<(), (YamlErrorType, ~str)>
    {
        let c_anchor = anchor.map(|s| { s.to_c_str() });
        let anchor_ptr = match c_anchor {
            Some(s) => s.with_ref(|ptr| { ptr }),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| { s.to_c_str() });
        let tag_ptr = match c_tag {
            Some(s) => s.with_ref(|ptr| { ptr }),
            None => ptr::null()
        };
        let c_plain_implicit = if plain_implicit { 1 } else { 0 };
        let c_quoted_implicit = if quoted_implicit { 1 } else { 0 };

        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_scalar_event_initialize(&mut event,
                    anchor_ptr as *ffi::yaml_char_t, tag_ptr as *ffi::yaml_char_t,
                    value.as_ptr(), value.len() as libc::c_int,
                    c_plain_implicit, c_quoted_implicit,
                    style) == 0
            {
                fail!("yaml_scalar_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_sequence_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
        style: ffi::YamlSequenceStyle) -> Result<(), (YamlErrorType, ~str)>
    {
        let c_anchor = anchor.map(|s| { s.to_c_str() });
        let anchor_ptr = match c_anchor {
            Some(s) => s.with_ref(|ptr| { ptr }),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| { s.to_c_str() });
        let tag_ptr = match c_tag {
            Some(s) => s.with_ref(|ptr| { ptr }),
            None => ptr::null()
        };
        let c_implicit = if implicit { 1 } else { 0 };

        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_sequence_start_event_initialize(&mut event,
                    anchor_ptr as *ffi::yaml_char_t, tag_ptr as *ffi::yaml_char_t,
                    c_implicit, style) == 0
            {
                fail!("yaml_sequence_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_sequence_end_event(&mut self) -> Result<(), (YamlErrorType, ~str)> {
        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_sequence_end_event_initialize(&mut event) == 0 {
                fail!("yaml_sequence_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_mapping_start_event(&mut self, anchor: Option<&str>, tag: Option<&str>, implicit: bool,
        style: ffi::YamlSequenceStyle) -> Result<(), (YamlErrorType, ~str)>
    {
        let c_anchor = anchor.map(|s| { s.to_c_str() });
        let anchor_ptr = match c_anchor {
            Some(s) => s.with_ref(|ptr| { ptr }),
            None => ptr::null()
        };
        let c_tag = tag.map(|s| { s.to_c_str() });
        let tag_ptr = match c_tag {
            Some(s) => s.with_ref(|ptr| { ptr }),
            None => ptr::null()
        };
        let c_implicit = if implicit { 1 } else { 0 };

        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_mapping_start_event_initialize(&mut event,
                    anchor_ptr as *ffi::yaml_char_t, tag_ptr as *ffi::yaml_char_t,
                    c_implicit, style) == 0
            {
                fail!("yaml_mapping_start_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn emit_mapping_end_event(&mut self) -> Result<(), (YamlErrorType, ~str)> {
        let mut event = ffi::yaml_event_t::new();
        unsafe {
            if ffi::yaml_mapping_end_event_initialize(&mut event) == 0 {
                fail!("yaml_mapping_end_event_initialize failed!");
            }

            if ffi::yaml_emitter_emit(&mut self.base_emitter.emitter_mem, &mut event) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }

    pub fn flush(&mut self) -> Result<(), (YamlErrorType, ~str)> {
        unsafe {
            if ffi::yaml_emitter_flush(&mut self.base_emitter.emitter_mem) != 0 {
                Ok(())
            } else {
                Err(self.get_error())
            }
        }
    }
}

extern fn handle_writer_cb(data: *mut YamlEmitter, buffer: *u8, size: libc::size_t) -> libc::c_int {
    unsafe {
        let buf = CVec::new(buffer as *mut u8, size as uint);
        let emitter = &mut *data;
        match emitter.writer.write(buf.as_slice()) {
            Ok(()) => 1,
            Err(_) => 0
        }
    }
}

#[cfg(test)]
mod test {
    use std::io::MemWriter;
    use emitter::YamlEmitter;
    use ffi::{YamlUtf8Encoding, YamlPlainScalarStyle, YamlFlowSequenceStyle};

    #[test]
    #[allow(unused_must_use)]
    fn event_emitter_sequence_test() {
        let mut writer = MemWriter::new();
        {
            let mut emitter = YamlEmitter::init(&mut writer);
            emitter.emit_stream_start_event(YamlUtf8Encoding);
            emitter.emit_document_start_event(None, [], true);
            emitter.emit_sequence_start_event(None, None, true, YamlFlowSequenceStyle);
            emitter.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle);
            emitter.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle);
            emitter.emit_sequence_end_event();
            emitter.emit_document_end_event(false);
            emitter.emit_stream_end_event();
            emitter.flush();
        }
        assert_eq!(writer.get_ref(), "[1, 2]\n...\n".as_bytes());
    }

    #[test]
    #[allow(unused_must_use)]
    fn event_emitter_mapping_test() {
        let mut writer = MemWriter::new();
        {
            let mut emitter = YamlEmitter::init(&mut writer);
            emitter.emit_stream_start_event(YamlUtf8Encoding);
            emitter.emit_document_start_event(None, [], true);
            emitter.emit_mapping_start_event(None, None, true, YamlFlowSequenceStyle);
            emitter.emit_scalar_event(None, None, "a", true, false, YamlPlainScalarStyle);
            emitter.emit_scalar_event(None, None, "1", true, false, YamlPlainScalarStyle);
            emitter.emit_scalar_event(None, None, "b", true, false, YamlPlainScalarStyle);
            emitter.emit_scalar_event(None, None, "2", true, false, YamlPlainScalarStyle);
            emitter.emit_mapping_end_event();
            emitter.emit_document_end_event(false);
            emitter.emit_stream_end_event();
            emitter.flush();
        }
        assert_eq!(writer.get_ref(), "{a: 1, b: 2}\n...\n".as_bytes());
    }
}
<|endoftext|>