<commit_before>//! Serializable and deserializable protocol messages.

// Nom has lots of unused warnings atm, keep this here for now.
#![allow(unused)]

use std::io::{self, Write};

use protocol::PeerProtocol;
use manager::ManagedMessage;

use bytes::Bytes;
use byteorder::{WriteBytesExt, BigEndian};
use nom::{IResult, be_u32, be_u8};

// TODO: Propogate failures to cast values to/from usize

const KEEP_ALIVE_MESSAGE_LEN:    u32 = 0;
const CHOKE_MESSAGE_LEN:         u32 = 1;
const UNCHOKE_MESSAGE_LEN:       u32 = 1;
const INTERESTED_MESSAGE_LEN:    u32 = 1;
const UNINTERESTED_MESSAGE_LEN:  u32 = 1;
const HAVE_MESSAGE_LEN:          u32 = 5;
const BASE_BITFIELD_MESSAGE_LEN: u32 = 1;
const REQUEST_MESSAGE_LEN:       u32 = 13;
const BASE_PIECE_MESSAGE_LEN:    u32 = 9;
const CANCEL_MESSAGE_LEN:        u32 = 13;

const CHOKE_MESSAGE_ID:        u8 = 0;
const UNCHOKE_MESSAGE_ID:      u8 = 1;
const INTERESTED_MESSAGE_ID:   u8 = 2;
const UNINTERESTED_MESSAGE_ID: u8 = 3;
const HAVE_MESSAGE_ID:         u8 = 4;
const BITFIELD_MESSAGE_ID:     u8 = 5;
const REQUEST_MESSAGE_ID:      u8 = 6;
const PIECE_MESSAGE_ID:        u8 = 7;
const CANCEL_MESSAGE_ID:       u8 = 8;

const MESSAGE_LENGTH_LEN_BYTES: usize = 4;
const MESSAGE_ID_LEN_BYTES:     usize = 1;
const HEADER_LEN:               usize = MESSAGE_LENGTH_LEN_BYTES + MESSAGE_ID_LEN_BYTES;

mod bits_extension;
mod standard;
mod null;

pub use message::bits_extension::{BitsExtensionMessage, PortMessage};
pub use message::standard::{HaveMessage, BitFieldMessage, RequestMessage, PieceMessage, CancelMessage};
pub use message::null::NullProtocolMessage;

/// Enumeration of messages for `PeerWireProtocol`.
pub enum PeerWireProtocolMessage
 where P: PeerProtocol {
    /// Message to keep the connection alive.
    KeepAlive,
    /// Message to tell a peer we will not be responding to their requests.
    ///
    /// Peers may wish to send *Interested and/or KeepAlive messages.
    Choke,
    /// Message to tell a peer we will now be responding to their requests.
    UnChoke,
    /// Message to tell a peer we are interested in downloading pieces from them.
    Interested,
    /// Message to tell a peer we are not interested in downloading pieces from them.
    UnInterested,
    /// Message to tell a peer we have some (validated) piece.
    Have(HaveMessage),
    /// Message to effectively send multiple HaveMessages in a single message.
    ///
    /// This message is only valid when the connection is initiated with the peer.
    BitField(BitFieldMessage),
    /// Message to request a block from a peer.
    Request(RequestMessage),
    /// Message from a peer containing a block.
    Piece(PieceMessage),
    /// Message to cancel a block request from a peer.
    Cancel(CancelMessage),
    /// Extension messages which are activated via the `ExtensionBits` as part of the handshake.
    BitsExtension(BitsExtensionMessage),
    /// Extension messages which are activated via the Extension Protocol.
    ///
    /// In reality, this can be any type that implements `ProtocolMessage` if, for example,
    /// you are running a private swarm where you know all nodes support a given message(s).
    ProtExtension(P::ProtocolMessage)
}

impl
 ManagedMessage for PeerWireProtocolMessage

    where P: PeerProtocol {
    fn keep_alive() -> PeerWireProtocolMessage
 {
        PeerWireProtocolMessage::KeepAlive
    }

    fn is_keep_alive(&self) -> bool {
        match self {
            &PeerWireProtocolMessage::KeepAlive => true,
            _                                   => false
        }
    }
}

impl
 PeerWireProtocolMessage

    where P: PeerProtocol {
    pub fn bytes_needed(bytes: &[u8], _ext_protocol: &mut P) -> io::Result<Option<usize>> {
        match be_u32(bytes) {
            IResult::Done(left, length) => Ok(Some(u32_to_usize(length))),
            _                           => Ok(None)
        }
    }

    pub fn parse_bytes(bytes: Bytes, ext_protocol: &mut P) -> io::Result<PeerWireProtocolMessage
> {
        match parse_message(bytes, ext_protocol) {
            IResult::Done(_, result) => result,
            _                        => Err(io::Error::new(io::ErrorKind::Other, "Failed To Parse PeerWireProtocolMessage"))
        }
    }

    pub fn write_bytes<W>(&self, mut writer: W, ext_protocol: &mut P) -> io::Result<()>
        where W: Write
    {
        match self {
            &PeerWireProtocolMessage::KeepAlive              => write_length_id_pair(writer, KEEP_ALIVE_MESSAGE_LEN, None),
            &PeerWireProtocolMessage::Choke                  => write_length_id_pair(writer, CHOKE_MESSAGE_LEN, Some(CHOKE_MESSAGE_ID)),
            &PeerWireProtocolMessage::UnChoke                => write_length_id_pair(writer, UNCHOKE_MESSAGE_LEN, Some(UNCHOKE_MESSAGE_ID)),
            &PeerWireProtocolMessage::Interested             => write_length_id_pair(writer, INTERESTED_MESSAGE_LEN, Some(INTERESTED_MESSAGE_ID)),
            &PeerWireProtocolMessage::UnInterested           => write_length_id_pair(writer, UNINTERESTED_MESSAGE_LEN, Some(UNINTERESTED_MESSAGE_ID)),
            &PeerWireProtocolMessage::Have(ref msg)          => msg.write_bytes(writer),
            &PeerWireProtocolMessage::BitField(ref msg)      => msg.write_bytes(writer),
            &PeerWireProtocolMessage::Request(ref msg)       => msg.write_bytes(writer),
            &PeerWireProtocolMessage::Piece(ref msg)         => msg.write_bytes(writer),
            &PeerWireProtocolMessage::Cancel(ref msg)        => msg.write_bytes(writer),
            &PeerWireProtocolMessage::BitsExtension(ref ext) => ext.write_bytes(writer),
            &PeerWireProtocolMessage::ProtExtension(ref ext) => ext_protocol.write_bytes(ext, writer)
        }
    }

    pub fn message_size(&self, ext_protocol: &mut P) -> usize {
        let message_specific_len = match self {
            &PeerWireProtocolMessage::KeepAlive              => KEEP_ALIVE_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::Choke                  => CHOKE_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::UnChoke                => UNCHOKE_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::Interested             => INTERESTED_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::UnInterested           => UNINTERESTED_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::Have(ref msg)          => HAVE_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::BitField(ref msg)      => BASE_BITFIELD_MESSAGE_LEN as usize + msg.bitfield().len(),
            &PeerWireProtocolMessage::Request(ref msg)       => REQUEST_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::Piece(ref msg)         => BASE_PIECE_MESSAGE_LEN as usize + msg.block().len(),
            &PeerWireProtocolMessage::Cancel(ref msg)        => CANCEL_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::BitsExtension(ref ext) => ext.message_size(),
            &PeerWireProtocolMessage::ProtExtension(ref ext) => ext_protocol.message_size(ext)
        };

        MESSAGE_LENGTH_LEN_BYTES + message_specific_len
    }
}

/// Write a length and optional id out to the given writer.
fn write_length_id_pair<W>(mut writer: W, length: u32, opt_id: Option<u8>) -> io::Result<()>
    where W: Write
{
    try!(writer.write_u32::<BigEndian>(length));

    if let Some(id) = opt_id {
        writer.write_u8(id)
    } else {
        Ok(())
    }
}

/// Parse the length portion of a message.
///
/// Panics if parsing failed for any reason.
fn parse_message_length(bytes: &[u8]) -> usize {
    if let IResult::Done(_, len) = be_u32(bytes) {
        u32_to_usize(len)
    } else {
        panic!("bip_peer: Message Length Was Less Than 4 Bytes")
    }
}

/// Panics if the conversion from a u32 to usize is not valid.
fn u32_to_usize(value: u32) -> usize {
    if value as usize as u32 != value {
        panic!("bip_peer: Cannot Convert u32 To usize, usize Is Less Than 32-Bits")
    }

    value as usize
}

// Since these messages may come over a stream oriented protocol, if a message is incomplete
// the number of bytes needed will be returned. However, that number of bytes is on a per parser
// basis. If possible, we should return the number of bytes needed for the rest of the WHOLE message.
// This allows clients to only re invoke the parser when it knows it has enough of the data.
fn parse_message
(mut bytes: Bytes, ext_protocol: &mut P) -> IResult<(), io::Result<PeerWireProtocolMessage
>>
    where P: PeerProtocol {
    let header_bytes = bytes.clone();

    // Attempt to parse a built in message type, otherwise, see if it is an extension type.
    alt!((),
         ignore_input!(
             switch!(header_bytes.as_ref(), throwaway_input!(tuple!(be_u32, opt!(be_u8))),
                (KEEP_ALIVE_MESSAGE_LEN, None) => value!(
                    Ok(PeerWireProtocolMessage::KeepAlive)
                ) |
                (CHOKE_MESSAGE_LEN, Some(CHOKE_MESSAGE_ID)) => value!(
                    Ok(PeerWireProtocolMessage::Choke)
                ) |
                (UNCHOKE_MESSAGE_LEN, Some(UNCHOKE_MESSAGE_ID)) => value!(
                    Ok(PeerWireProtocolMessage::UnChoke)
                ) |
                (INTERESTED_MESSAGE_LEN, Some(INTERESTED_MESSAGE_ID)) => value!(
                    Ok(PeerWireProtocolMessage::Interested)
                ) |
                (UNINTERESTED_MESSAGE_LEN, Some(UNINTERESTED_MESSAGE_ID)) => value!(
                    Ok(PeerWireProtocolMessage::UnInterested)
                ) |
                (HAVE_MESSAGE_LEN, Some(HAVE_MESSAGE_ID)) => map!(
                    call!(HaveMessage::parse_bytes, bytes.split_off(HEADER_LEN)),
                    |res_have| res_have.map(|have| PeerWireProtocolMessage::Have(have))
                ) |
                (message_len, Some(BITFIELD_MESSAGE_ID)) => map!(
                    call!(BitFieldMessage::parse_bytes, bytes.split_off(HEADER_LEN), message_len - 1),
                    |res_bitfield| res_bitfield.map(|bitfield| PeerWireProtocolMessage::BitField(bitfield))
                ) |
                (REQUEST_MESSAGE_LEN, Some(REQUEST_MESSAGE_ID)) => map!(
                    call!(RequestMessage::parse_bytes, bytes.split_off(HEADER_LEN)),
                    |res_request| res_request.map(|request| PeerWireProtocolMessage::Request(request))
                ) |
                (message_len, Some(PIECE_MESSAGE_ID)) => map!(
                    call!(PieceMessage::parse_bytes, bytes.split_off(HEADER_LEN), message_len - 1),
                    |res_piece| res_piece.map(|piece| PeerWireProtocolMessage::Piece(piece))
                ) |
                (CANCEL_MESSAGE_LEN, Some(CANCEL_MESSAGE_ID)) => map!(
                    call!(CancelMessage::parse_bytes, bytes.split_off(HEADER_LEN)),
                    |res_cancel| res_cancel.map(|cancel| PeerWireProtocolMessage::Cancel(cancel))
                )
            )
         ) | map!(call!(BitsExtensionMessage::parse_bytes, bytes.clone()),
               |res_bits_ext| res_bits_ext.map(|bits_ext| PeerWireProtocolMessage::BitsExtension(bits_ext)))
           | map!(value!(ext_protocol.parse_bytes(bytes)),
               |res_prot_ext| res_prot_ext.map(|prot_ext| PeerWireProtocolMessage::ProtExtension(prot_ext)))
    )
}<commit_msg>Add Message Length Length To bytes_needed<commit_after>//! Serializable and deserializable protocol messages.

// Nom has lots of unused warnings atm, keep this here for now.
#![allow(unused)]

use std::io::{self, Write};

use protocol::PeerProtocol;
use manager::ManagedMessage;

use bytes::Bytes;
use byteorder::{WriteBytesExt, BigEndian};
use nom::{IResult, be_u32, be_u8};

// TODO: Propogate failures to cast values to/from usize

const KEEP_ALIVE_MESSAGE_LEN:    u32 = 0;
const CHOKE_MESSAGE_LEN:         u32 = 1;
const UNCHOKE_MESSAGE_LEN:       u32 = 1;
const INTERESTED_MESSAGE_LEN:    u32 = 1;
const UNINTERESTED_MESSAGE_LEN:  u32 = 1;
const HAVE_MESSAGE_LEN:          u32 = 5;
const BASE_BITFIELD_MESSAGE_LEN: u32 = 1;
const REQUEST_MESSAGE_LEN:       u32 = 13;
const BASE_PIECE_MESSAGE_LEN:    u32 = 9;
const CANCEL_MESSAGE_LEN:        u32 = 13;

const CHOKE_MESSAGE_ID:        u8 = 0;
const UNCHOKE_MESSAGE_ID:      u8 = 1;
const INTERESTED_MESSAGE_ID:   u8 = 2;
const UNINTERESTED_MESSAGE_ID: u8 = 3;
const HAVE_MESSAGE_ID:         u8 = 4;
const BITFIELD_MESSAGE_ID:     u8 = 5;
const REQUEST_MESSAGE_ID:      u8 = 6;
const PIECE_MESSAGE_ID:        u8 = 7;
const CANCEL_MESSAGE_ID:       u8 = 8;

const MESSAGE_LENGTH_LEN_BYTES: usize = 4;
const MESSAGE_ID_LEN_BYTES:     usize = 1;
const HEADER_LEN:               usize = MESSAGE_LENGTH_LEN_BYTES + MESSAGE_ID_LEN_BYTES;

mod bits_extension;
mod standard;
mod null;

pub use message::bits_extension::{BitsExtensionMessage, PortMessage};
pub use message::standard::{HaveMessage, BitFieldMessage, RequestMessage, PieceMessage, CancelMessage};
pub use message::null::NullProtocolMessage;

/// Enumeration of messages for `PeerWireProtocol`.
pub enum PeerWireProtocolMessage
 where P: PeerProtocol {
    /// Message to keep the connection alive.
    KeepAlive,
    /// Message to tell a peer we will not be responding to their requests.
    ///
    /// Peers may wish to send *Interested and/or KeepAlive messages.
    Choke,
    /// Message to tell a peer we will now be responding to their requests.
    UnChoke,
    /// Message to tell a peer we are interested in downloading pieces from them.
    Interested,
    /// Message to tell a peer we are not interested in downloading pieces from them.
    UnInterested,
    /// Message to tell a peer we have some (validated) piece.
    Have(HaveMessage),
    /// Message to effectively send multiple HaveMessages in a single message.
    ///
    /// This message is only valid when the connection is initiated with the peer.
    BitField(BitFieldMessage),
    /// Message to request a block from a peer.
    Request(RequestMessage),
    /// Message from a peer containing a block.
    Piece(PieceMessage),
    /// Message to cancel a block request from a peer.
    Cancel(CancelMessage),
    /// Extension messages which are activated via the `ExtensionBits` as part of the handshake.
    BitsExtension(BitsExtensionMessage),
    /// Extension messages which are activated via the Extension Protocol.
    ///
    /// In reality, this can be any type that implements `ProtocolMessage` if, for example,
    /// you are running a private swarm where you know all nodes support a given message(s).
    ProtExtension(P::ProtocolMessage)
}

impl
 ManagedMessage for PeerWireProtocolMessage

    where P: PeerProtocol {
    fn keep_alive() -> PeerWireProtocolMessage
 {
        PeerWireProtocolMessage::KeepAlive
    }

    fn is_keep_alive(&self) -> bool {
        match self {
            &PeerWireProtocolMessage::KeepAlive => true,
            _                                   => false
        }
    }
}

impl
 PeerWireProtocolMessage

    where P: PeerProtocol {
    pub fn bytes_needed(bytes: &[u8], _ext_protocol: &mut P) -> io::Result<Option<usize>> {
        match be_u32(bytes) {
            // We need 4 bytes for the length, plus whatever the length is...
            IResult::Done(left, length) => Ok(Some(MESSAGE_LENGTH_LEN_BYTES + u32_to_usize(length))),
            _                           => Ok(None)
        }
    }

    pub fn parse_bytes(bytes: Bytes, ext_protocol: &mut P) -> io::Result<PeerWireProtocolMessage
> {
        match parse_message(bytes, ext_protocol) {
            IResult::Done(_, result) => result,
            _                        => Err(io::Error::new(io::ErrorKind::Other, "Failed To Parse PeerWireProtocolMessage"))
        }
    }

    pub fn write_bytes<W>(&self, mut writer: W, ext_protocol: &mut P) -> io::Result<()>
        where W: Write
    {
        match self {
            &PeerWireProtocolMessage::KeepAlive              => write_length_id_pair(writer, KEEP_ALIVE_MESSAGE_LEN, None),
            &PeerWireProtocolMessage::Choke                  => write_length_id_pair(writer, CHOKE_MESSAGE_LEN, Some(CHOKE_MESSAGE_ID)),
            &PeerWireProtocolMessage::UnChoke                => write_length_id_pair(writer, UNCHOKE_MESSAGE_LEN, Some(UNCHOKE_MESSAGE_ID)),
            &PeerWireProtocolMessage::Interested             => write_length_id_pair(writer, INTERESTED_MESSAGE_LEN, Some(INTERESTED_MESSAGE_ID)),
            &PeerWireProtocolMessage::UnInterested           => write_length_id_pair(writer, UNINTERESTED_MESSAGE_LEN, Some(UNINTERESTED_MESSAGE_ID)),
            &PeerWireProtocolMessage::Have(ref msg)          => msg.write_bytes(writer),
            &PeerWireProtocolMessage::BitField(ref msg)      => msg.write_bytes(writer),
            &PeerWireProtocolMessage::Request(ref msg)       => msg.write_bytes(writer),
            &PeerWireProtocolMessage::Piece(ref msg)         => msg.write_bytes(writer),
            &PeerWireProtocolMessage::Cancel(ref msg)        => msg.write_bytes(writer),
            &PeerWireProtocolMessage::BitsExtension(ref ext) => ext.write_bytes(writer),
            &PeerWireProtocolMessage::ProtExtension(ref ext) => ext_protocol.write_bytes(ext, writer)
        }
    }

    pub fn message_size(&self, ext_protocol: &mut P) -> usize {
        let message_specific_len = match self {
            &PeerWireProtocolMessage::KeepAlive              => KEEP_ALIVE_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::Choke                  => CHOKE_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::UnChoke                => UNCHOKE_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::Interested             => INTERESTED_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::UnInterested           => UNINTERESTED_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::Have(ref msg)          => HAVE_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::BitField(ref msg)      => BASE_BITFIELD_MESSAGE_LEN as usize + msg.bitfield().len(),
            &PeerWireProtocolMessage::Request(ref msg)       => REQUEST_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::Piece(ref msg)         => BASE_PIECE_MESSAGE_LEN as usize + msg.block().len(),
            &PeerWireProtocolMessage::Cancel(ref msg)        => CANCEL_MESSAGE_LEN as usize,
            &PeerWireProtocolMessage::BitsExtension(ref ext) => ext.message_size(),
            &PeerWireProtocolMessage::ProtExtension(ref ext) => ext_protocol.message_size(ext)
        };

        MESSAGE_LENGTH_LEN_BYTES + message_specific_len
    }
}

/// Write a length and optional id out to the given writer.
fn write_length_id_pair<W>(mut writer: W, length: u32, opt_id: Option<u8>) -> io::Result<()>
    where W: Write
{
    try!(writer.write_u32::<BigEndian>(length));

    if let Some(id) = opt_id {
        writer.write_u8(id)
    } else {
        Ok(())
    }
}

/// Parse the length portion of a message.
///
/// Panics if parsing failed for any reason.
fn parse_message_length(bytes: &[u8]) -> usize {
    if let IResult::Done(_, len) = be_u32(bytes) {
        u32_to_usize(len)
    } else {
        panic!("bip_peer: Message Length Was Less Than 4 Bytes")
    }
}

/// Panics if the conversion from a u32 to usize is not valid.
fn u32_to_usize(value: u32) -> usize {
    if value as usize as u32 != value {
        panic!("bip_peer: Cannot Convert u32 To usize, usize Is Less Than 32-Bits")
    }

    value as usize
}

// Since these messages may come over a stream oriented protocol, if a message is incomplete
// the number of bytes needed will be returned. However, that number of bytes is on a per parser
// basis. If possible, we should return the number of bytes needed for the rest of the WHOLE message.
// This allows clients to only re invoke the parser when it knows it has enough of the data.
fn parse_message
(mut bytes: Bytes, ext_protocol: &mut P) -> IResult<(), io::Result<PeerWireProtocolMessage
>>
    where P: PeerProtocol {
    let header_bytes = bytes.clone();

    // Attempt to parse a built in message type, otherwise, see if it is an extension type.
    alt!((),
         ignore_input!(
             switch!(header_bytes.as_ref(), throwaway_input!(tuple!(be_u32, opt!(be_u8))),
                (KEEP_ALIVE_MESSAGE_LEN, None) => value!(
                    Ok(PeerWireProtocolMessage::KeepAlive)
                ) |
                (CHOKE_MESSAGE_LEN, Some(CHOKE_MESSAGE_ID)) => value!(
                    Ok(PeerWireProtocolMessage::Choke)
                ) |
                (UNCHOKE_MESSAGE_LEN, Some(UNCHOKE_MESSAGE_ID)) => value!(
                    Ok(PeerWireProtocolMessage::UnChoke)
                ) |
                (INTERESTED_MESSAGE_LEN, Some(INTERESTED_MESSAGE_ID)) => value!(
                    Ok(PeerWireProtocolMessage::Interested)
                ) |
                (UNINTERESTED_MESSAGE_LEN, Some(UNINTERESTED_MESSAGE_ID)) => value!(
                    Ok(PeerWireProtocolMessage::UnInterested)
                ) |
                (HAVE_MESSAGE_LEN, Some(HAVE_MESSAGE_ID)) => map!(
                    call!(HaveMessage::parse_bytes, bytes.split_off(HEADER_LEN)),
                    |res_have| res_have.map(|have| PeerWireProtocolMessage::Have(have))
                ) |
                (message_len, Some(BITFIELD_MESSAGE_ID)) => map!(
                    call!(BitFieldMessage::parse_bytes, bytes.split_off(HEADER_LEN), message_len - 1),
                    |res_bitfield| res_bitfield.map(|bitfield| PeerWireProtocolMessage::BitField(bitfield))
                ) |
                (REQUEST_MESSAGE_LEN, Some(REQUEST_MESSAGE_ID)) => map!(
                    call!(RequestMessage::parse_bytes, bytes.split_off(HEADER_LEN)),
                    |res_request| res_request.map(|request| PeerWireProtocolMessage::Request(request))
                ) |
                (message_len, Some(PIECE_MESSAGE_ID)) => map!(
                    call!(PieceMessage::parse_bytes, bytes.split_off(HEADER_LEN), message_len - 1),
                    |res_piece| res_piece.map(|piece| PeerWireProtocolMessage::Piece(piece))
                ) |
                (CANCEL_MESSAGE_LEN, Some(CANCEL_MESSAGE_ID)) => map!(
                    call!(CancelMessage::parse_bytes, bytes.split_off(HEADER_LEN)),
                    |res_cancel| res_cancel.map(|cancel| PeerWireProtocolMessage::Cancel(cancel))
                )
            )
         ) | map!(call!(BitsExtensionMessage::parse_bytes, bytes.clone()),
               |res_bits_ext| res_bits_ext.map(|bits_ext| PeerWireProtocolMessage::BitsExtension(bits_ext)))
           | map!(value!(ext_protocol.parse_bytes(bytes)),
               |res_prot_ext| res_prot_ext.map(|prot_ext| PeerWireProtocolMessage::ProtExtension(prot_ext)))
    )
}<|endoftext|>


<commit_before>use gdk_pixbuf::{PixbufLoader, PixbufLoaderExt};
use gio;
use markup5ever::{LocalName, Namespace, QualName};
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::rc::Rc;

use crate::allowed_url::{AllowedUrl, Fragment};
use crate::create_node::create_node;
use crate::css::CssRules;
use crate::error::LoadingError;
use crate::handle::LoadOptions;
use crate::io::{self, BinaryData};
use crate::node::{NodeCascade, NodeData, NodeType, RsvgNode};
use crate::properties::ComputedValues;
use crate::property_bag::PropertyBag;
use crate::structure::{IntrinsicDimensions, NodeSvg};
use crate::surface_utils::shared_surface::SharedImageSurface;
use crate::text::NodeChars;
use crate::xml::xml_load_from_possibly_compressed_stream;

/// A loaded SVG file and its derived data
///
/// This contains the tree of nodes (SVG elements), the mapping
/// of id to node, and the CSS styles defined for this SVG.
pub struct Document {
    tree: RsvgNode,

    ids: HashMap<String, RsvgNode>,

    // These require interior mutability because we load the extern
    // resources all over the place.  Eventually we'll be able to do this
    // once, at loading time, and keep this immutable.
    externs: RefCell<Resources>,
    images: RefCell<Images>,

    // Once we do not need to load externs, we can drop this as well
    load_options: LoadOptions,
}

impl Document {
    pub fn new(
        mut tree: RsvgNode,
        ids: HashMap<String, RsvgNode>,
        load_options: LoadOptions,
    ) -> Document {
        let values = ComputedValues::default();
        tree.cascade(&values);

        Document {
            tree,
            ids,
            externs: RefCell::new(Resources::new()),
            images: RefCell::new(Images::new()),
            load_options,
        }
    }

    pub fn load_from_stream(
        load_options: &LoadOptions,
        stream: &gio::InputStream,
        cancellable: Option<&gio::Cancellable>,
    ) -> Result<Document, LoadingError> {
        xml_load_from_possibly_compressed_stream(load_options, stream, cancellable)
    }

    pub fn root(&self) -> RsvgNode {
        self.tree.clone()
    }

    pub fn lookup(&self, fragment: &Fragment) -> Result<RsvgNode, LoadingError> {
        if fragment.uri().is_some() {
            self.externs
                .borrow_mut()
                .lookup(&self.load_options, fragment)
        } else {
            self.lookup_node_by_id(fragment.fragment())
                .ok_or(LoadingError::BadUrl)
        }
    }

    pub fn lookup_node_by_id(&self, id: &str) -> Option<RsvgNode> {
        self.ids.get(id).map(|n| (*n).clone())
    }

    pub fn lookup_image(&self, href: &str) -> Result<SharedImageSurface, LoadingError> {
        self.images.borrow_mut().lookup(&self.load_options, href)
    }

    pub fn get_intrinsic_dimensions(&self) -> IntrinsicDimensions {
        let root = self.root();
        let node_data = root.borrow();

        assert!(node_data.get_type() == NodeType::Svg);
        node_data.get_impl::<NodeSvg>().get_intrinsic_dimensions()
    }
}

struct Resources {
    resources: HashMap<AllowedUrl, Result<Rc<Document>, LoadingError>>,
}

impl Resources {
    pub fn new() -> Resources {
        Resources {
            resources: Default::default(),
        }
    }

    pub fn lookup(
        &mut self,
        load_options: &LoadOptions,
        fragment: &Fragment,
    ) -> Result<RsvgNode, LoadingError> {
        if let Some(ref href) = fragment.uri() {
            self.get_extern_document(load_options, href)
                .and_then(|doc| {
                    doc.lookup_node_by_id(fragment.fragment())
                        .ok_or(LoadingError::BadUrl)
                })
        } else {
            unreachable!();
        }
    }

    fn get_extern_document(
        &mut self,
        load_options: &LoadOptions,
        href: &str,
    ) -> Result<Rc<Document>, LoadingError> {
        let aurl = AllowedUrl::from_href(href, load_options.base_url.as_ref())
            .map_err(|_| LoadingError::BadUrl)?;

        match self.resources.entry(aurl) {
            Entry::Occupied(e) => e.get().clone(),
            Entry::Vacant(e) => {
                let aurl = e.key();
                // FIXME: pass a cancellable to these
                let doc = io::acquire_stream(aurl, None)
                    .and_then(|stream| {
                        Document::load_from_stream(
                            &load_options.copy_with_base_url(aurl),
                            &stream,
                            None,
                        )
                    })
                    .map(Rc::new);
                let res = e.insert(doc);
                res.clone()
            }
        }
    }
}

struct Images {
    images: HashMap<AllowedUrl, Result<SharedImageSurface, LoadingError>>,
}

impl Images {
    pub fn new() -> Images {
        Images {
            images: Default::default(),
        }
    }

    pub fn lookup(
        &mut self,
        load_options: &LoadOptions,
        href: &str,
    ) -> Result<SharedImageSurface, LoadingError> {
        let aurl = AllowedUrl::from_href(href, load_options.base_url.as_ref())
            .map_err(|_| LoadingError::BadUrl)?;

        match self.images.entry(aurl) {
            Entry::Occupied(e) => e.get().clone(),
            Entry::Vacant(e) => {
                let surface = load_image(load_options, e.key());
                let res = e.insert(surface);
                res.clone()
            }
        }
    }
}

fn load_image(
    load_options: &LoadOptions,
    aurl: &AllowedUrl,
) -> Result<SharedImageSurface, LoadingError> {
    let BinaryData {
        data: bytes,
        content_type,
    } = io::acquire_data(&aurl, None)?;

    if bytes.is_empty() {
        return Err(LoadingError::EmptyData);
    }

    let loader = if let Some(ref content_type) = content_type {
        PixbufLoader::new_with_mime_type(content_type)?
    } else {
        PixbufLoader::new()
    };

    loader.write(&bytes)?;
    loader.close()?;

    let pixbuf = loader.get_pixbuf().ok_or(LoadingError::Unknown)?;

    let bytes = if load_options.keep_image_data {
        Some(bytes)
    } else {
        None
    };

    let surface =
        SharedImageSurface::from_pixbuf(&pixbuf, bytes, content_type.as_ref().map(String::as_str))?;

    Ok(surface)
}

pub struct DocumentBuilder {
    load_options: LoadOptions,
    tree: Option<RsvgNode>,
    ids: HashMap<String, RsvgNode>,
    css_rules: CssRules,
}

impl DocumentBuilder {
    pub fn new(load_options: &LoadOptions) -> DocumentBuilder {
        DocumentBuilder {
            load_options: load_options.clone(),
            tree: None,
            ids: HashMap::new(),
            css_rules: CssRules::default(),
        }
    }

    pub fn append_element(
        &mut self,
        name: &QualName,
        pbag: &PropertyBag,
        parent: Option<RsvgNode>,
    ) -> RsvgNode {
        let mut node = create_node(name, pbag);

        if let Some(id) = node.borrow().get_id() {
            // This is so we don't overwrite an existing id
            self.ids
                .entry(id.to_string())
                .or_insert_with(|| node.clone());
        }

        node.borrow_mut()
            .set_atts(parent.as_ref().clone(), pbag, self.load_options.locale());

        if let Some(mut parent) = parent {
            parent.append(node.clone());
        } else if self.tree.is_none() {
            self.tree = Some(node.clone());
        } else {
            panic!("The tree root has already been set");
        }

        node
    }

    pub fn append_characters(&mut self, text: &str, parent: &mut RsvgNode) {
        if text.is_empty() {
            return;
        }

        // When the last child is a Chars node we can coalesce
        // the text and avoid screwing up the Pango layouts
        let chars_node = if let Some(child) = parent
            .last_child()
            .filter(|c| c.borrow().get_type() == NodeType::Chars)
        {
            child
        } else {
            let child = RsvgNode::new(NodeData::new(
                NodeType::Chars,
                &QualName::new(
                    None,
                    Namespace::from("https://wiki.gnome.org/Projects/LibRsvg"),
                    LocalName::from("rsvg-chars"),
                ),
                None,
                None,
                Box::new(NodeChars::new()),
            ));

            parent.append(child.clone());

            child
        };

        chars_node.borrow().get_impl::<NodeChars>().append(text);
    }

    pub fn load_css(&mut self, url: &AllowedUrl) {
        // FIXME: handle CSS errors
        let _ = self.css_rules.load_css(&url);
    }

    pub fn parse_css(&mut self, css_data: &str) {
        self.css_rules
            .parse(self.load_options.base_url.as_ref(), css_data);
    }

    pub fn build(mut self) -> Result<Document, LoadingError> {
        match self.tree {
            None => Err(LoadingError::SvgHasNoElements),
            Some(ref root) if root.borrow().get_type() == NodeType::Svg => {
                for mut node in root.descendants() {
                    node.borrow_mut().set_style(&self.css_rules);
                }

                Ok(Document::new(
                    self.tree.take().unwrap(),
                    self.ids,
                    self.load_options.clone(),
                ))
            }
            _ => Err(LoadingError::RootElementIsNotSvg),
        }
    }
}
<commit_msg>document: shorten code<commit_after>use gdk_pixbuf::{PixbufLoader, PixbufLoaderExt};
use gio;
use markup5ever::{LocalName, Namespace, QualName};
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::rc::Rc;

use crate::allowed_url::{AllowedUrl, Fragment};
use crate::create_node::create_node;
use crate::css::CssRules;
use crate::error::LoadingError;
use crate::handle::LoadOptions;
use crate::io::{self, BinaryData};
use crate::node::{NodeCascade, NodeData, NodeType, RsvgNode};
use crate::properties::ComputedValues;
use crate::property_bag::PropertyBag;
use crate::structure::{IntrinsicDimensions, NodeSvg};
use crate::surface_utils::shared_surface::SharedImageSurface;
use crate::text::NodeChars;
use crate::xml::xml_load_from_possibly_compressed_stream;

/// A loaded SVG file and its derived data
///
/// This contains the tree of nodes (SVG elements), the mapping
/// of id to node, and the CSS styles defined for this SVG.
pub struct Document {
    tree: RsvgNode,

    ids: HashMap<String, RsvgNode>,

    // These require interior mutability because we load the extern
    // resources all over the place.  Eventually we'll be able to do this
    // once, at loading time, and keep this immutable.
    externs: RefCell<Resources>,
    images: RefCell<Images>,

    // Once we do not need to load externs, we can drop this as well
    load_options: LoadOptions,
}

impl Document {
    pub fn load_from_stream(
        load_options: &LoadOptions,
        stream: &gio::InputStream,
        cancellable: Option<&gio::Cancellable>,
    ) -> Result<Document, LoadingError> {
        xml_load_from_possibly_compressed_stream(load_options, stream, cancellable)
    }

    pub fn root(&self) -> RsvgNode {
        self.tree.clone()
    }

    pub fn lookup(&self, fragment: &Fragment) -> Result<RsvgNode, LoadingError> {
        if fragment.uri().is_some() {
            self.externs
                .borrow_mut()
                .lookup(&self.load_options, fragment)
        } else {
            self.lookup_node_by_id(fragment.fragment())
                .ok_or(LoadingError::BadUrl)
        }
    }

    pub fn lookup_node_by_id(&self, id: &str) -> Option<RsvgNode> {
        self.ids.get(id).map(|n| (*n).clone())
    }

    pub fn lookup_image(&self, href: &str) -> Result<SharedImageSurface, LoadingError> {
        self.images.borrow_mut().lookup(&self.load_options, href)
    }

    pub fn get_intrinsic_dimensions(&self) -> IntrinsicDimensions {
        let root = self.root();
        let node_data = root.borrow();

        assert!(node_data.get_type() == NodeType::Svg);
        node_data.get_impl::<NodeSvg>().get_intrinsic_dimensions()
    }
}

struct Resources {
    resources: HashMap<AllowedUrl, Result<Rc<Document>, LoadingError>>,
}

impl Resources {
    pub fn new() -> Resources {
        Resources {
            resources: Default::default(),
        }
    }

    pub fn lookup(
        &mut self,
        load_options: &LoadOptions,
        fragment: &Fragment,
    ) -> Result<RsvgNode, LoadingError> {
        if let Some(ref href) = fragment.uri() {
            self.get_extern_document(load_options, href)
                .and_then(|doc| {
                    doc.lookup_node_by_id(fragment.fragment())
                        .ok_or(LoadingError::BadUrl)
                })
        } else {
            unreachable!();
        }
    }

    fn get_extern_document(
        &mut self,
        load_options: &LoadOptions,
        href: &str,
    ) -> Result<Rc<Document>, LoadingError> {
        let aurl = AllowedUrl::from_href(href, load_options.base_url.as_ref())
            .map_err(|_| LoadingError::BadUrl)?;

        match self.resources.entry(aurl) {
            Entry::Occupied(e) => e.get().clone(),
            Entry::Vacant(e) => {
                let aurl = e.key();
                // FIXME: pass a cancellable to these
                let doc = io::acquire_stream(aurl, None)
                    .and_then(|stream| {
                        Document::load_from_stream(
                            &load_options.copy_with_base_url(aurl),
                            &stream,
                            None,
                        )
                    })
                    .map(Rc::new);
                let res = e.insert(doc);
                res.clone()
            }
        }
    }
}

struct Images {
    images: HashMap<AllowedUrl, Result<SharedImageSurface, LoadingError>>,
}

impl Images {
    pub fn new() -> Images {
        Images {
            images: Default::default(),
        }
    }

    pub fn lookup(
        &mut self,
        load_options: &LoadOptions,
        href: &str,
    ) -> Result<SharedImageSurface, LoadingError> {
        let aurl = AllowedUrl::from_href(href, load_options.base_url.as_ref())
            .map_err(|_| LoadingError::BadUrl)?;

        match self.images.entry(aurl) {
            Entry::Occupied(e) => e.get().clone(),
            Entry::Vacant(e) => {
                let surface = load_image(load_options, e.key());
                let res = e.insert(surface);
                res.clone()
            }
        }
    }
}

fn load_image(
    load_options: &LoadOptions,
    aurl: &AllowedUrl,
) -> Result<SharedImageSurface, LoadingError> {
    let BinaryData {
        data: bytes,
        content_type,
    } = io::acquire_data(&aurl, None)?;

    if bytes.is_empty() {
        return Err(LoadingError::EmptyData);
    }

    let loader = if let Some(ref content_type) = content_type {
        PixbufLoader::new_with_mime_type(content_type)?
    } else {
        PixbufLoader::new()
    };

    loader.write(&bytes)?;
    loader.close()?;

    let pixbuf = loader.get_pixbuf().ok_or(LoadingError::Unknown)?;

    let bytes = if load_options.keep_image_data {
        Some(bytes)
    } else {
        None
    };

    let surface =
        SharedImageSurface::from_pixbuf(&pixbuf, bytes, content_type.as_ref().map(String::as_str))?;

    Ok(surface)
}

pub struct DocumentBuilder {
    load_options: LoadOptions,
    tree: Option<RsvgNode>,
    ids: HashMap<String, RsvgNode>,
    css_rules: CssRules,
}

impl DocumentBuilder {
    pub fn new(load_options: &LoadOptions) -> DocumentBuilder {
        DocumentBuilder {
            load_options: load_options.clone(),
            tree: None,
            ids: HashMap::new(),
            css_rules: CssRules::default(),
        }
    }

    pub fn append_element(
        &mut self,
        name: &QualName,
        pbag: &PropertyBag,
        parent: Option<RsvgNode>,
    ) -> RsvgNode {
        let mut node = create_node(name, pbag);

        if let Some(id) = node.borrow().get_id() {
            // This is so we don't overwrite an existing id
            self.ids
                .entry(id.to_string())
                .or_insert_with(|| node.clone());
        }

        node.borrow_mut()
            .set_atts(parent.as_ref().clone(), pbag, self.load_options.locale());

        if let Some(mut parent) = parent {
            parent.append(node.clone());
        } else if self.tree.is_none() {
            self.tree = Some(node.clone());
        } else {
            panic!("The tree root has already been set");
        }

        node
    }

    pub fn append_characters(&mut self, text: &str, parent: &mut RsvgNode) {
        if text.is_empty() {
            return;
        }

        // When the last child is a Chars node we can coalesce
        // the text and avoid screwing up the Pango layouts
        let chars_node = if let Some(child) = parent
            .last_child()
            .filter(|c| c.borrow().get_type() == NodeType::Chars)
        {
            child
        } else {
            let child = RsvgNode::new(NodeData::new(
                NodeType::Chars,
                &QualName::new(
                    None,
                    Namespace::from("https://wiki.gnome.org/Projects/LibRsvg"),
                    LocalName::from("rsvg-chars"),
                ),
                None,
                None,
                Box::new(NodeChars::new()),
            ));

            parent.append(child.clone());

            child
        };

        chars_node.borrow().get_impl::<NodeChars>().append(text);
    }

    pub fn load_css(&mut self, url: &AllowedUrl) {
        // FIXME: handle CSS errors
        let _ = self.css_rules.load_css(&url);
    }

    pub fn parse_css(&mut self, css_data: &str) {
        self.css_rules
            .parse(self.load_options.base_url.as_ref(), css_data);
    }

    pub fn build(mut self) -> Result<Document, LoadingError> {
        match self.tree {
            None => Err(LoadingError::SvgHasNoElements),
            Some(ref mut root) if root.borrow().get_type() == NodeType::Svg => {
                for mut node in root.descendants() {
                    node.borrow_mut().set_style(&self.css_rules);
                }

                let values = ComputedValues::default();
                root.cascade(&values);

                Ok(Document {
                    tree: self.tree.take().unwrap(),
                    ids: self.ids,
                    externs: RefCell::new(Resources::new()),
                    images: RefCell::new(Images::new()),
                    load_options: self.load_options.clone(),
                })
            }
            _ => Err(LoadingError::RootElementIsNotSvg),
        }
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::{Encodable, Encoder, Decoder};
use std::collections::HashMap;

use yxorp::messages::{Command,HttpFront,TlsFront,Instance};

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct HttpProxyInstance {
  ip_address: String,
  port:       u16,
}

pub type AppId = String;

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct HttpProxyFront {
  app_id:     AppId,
  hostname:   String,
  path_begin: String,
}

#[derive(Debug,Clone,PartialEq,Eq,RustcDecodable, RustcEncodable)]
pub struct HttpProxy {
  ip_address: String,
  port:       u16,
  fronts:     HashMap<AppId, Vec<HttpProxyFront>>,
  instances:  HashMap<AppId, Vec<HttpProxyInstance>>,
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct TlsProxyFront {
  app_id:      AppId,
  hostname:    String,
  path_begin:  String,
  certificate: Vec<u8>,
  key:         Vec<u8>,
}

#[derive(Debug,Clone,PartialEq,Eq,RustcDecodable, RustcEncodable)]
pub struct TlsProxy {
  ip_address: String,
  port:       u16,
  fronts:     HashMap<AppId, Vec<TlsProxyFront>>,
  instances:  HashMap<AppId, Vec<HttpProxyInstance>>,
}

#[derive(Debug,Clone,PartialEq,Eq)]
pub enum ConfigState {
  Http(HttpProxy),
  Tls(TlsProxy),
}

impl ConfigState {
  pub fn handle_command(&mut self, command: &Command) {
    match *self {
      ConfigState::Http(ref mut state) => state.handle_command(command),
      ConfigState::Tls(ref mut state)  => state.handle_command(command),
    }
  }

  pub fn generate_commands(&self) -> Vec<Command> {
    match *self {
      ConfigState::Http(ref state) => state.generate_commands(),
      ConfigState::Tls(ref state)  => state.generate_commands(),
    }
  }
}

impl Encodable for ConfigState {
  fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
    match *self {
      ConfigState::Http(ref state) => state.encode(e),
      ConfigState::Tls(ref state)  => state.encode(e),
    }
  }
}

impl HttpProxy {
  pub fn new(ip: String, port: u16) -> HttpProxy {
    HttpProxy {
      ip_address: ip,
      port:       port,
      fronts:     HashMap::new(),
      instances:  HashMap::new(),
    }
  }

  pub fn handle_command(&mut self, command: &Command) {
    match command {
      &Command::AddHttpFront(ref front) => {
        let f = HttpProxyFront {
          app_id:     front.app_id.clone(),
          hostname:   front.hostname.clone(),
          path_begin: front.path_begin.clone(),
        };
        if self.fronts.contains_key(&front.app_id) {
          self.fronts.get_mut(&front.app_id).unwrap().push(f);
        } else {
          self.fronts.insert(front.app_id.clone(), vec!(f));
        }
      },
      &Command::RemoveHttpFront(ref front) => {
        if let Some(front_list) = self.fronts.get_mut(&front.app_id) {
          front_list.retain(|el| el.hostname != front.hostname || el.path_begin != front.path_begin);
        }
      },
      &Command::AddInstance(ref instance)  => {
        let inst = HttpProxyInstance {
          ip_address: instance.ip_address.clone(),
          port:       instance.port,
        };
        if self.instances.contains_key(&instance.app_id) {
          self.instances.get_mut(&instance.app_id).unwrap().push(inst);
        } else {
          self.instances.insert(instance.app_id.clone(), vec!(inst));
        }
      },
      &Command::RemoveInstance(ref instance) => {
        if let Some(instance_list) = self.instances.get_mut(&instance.app_id) {
          instance_list.retain(|el| el.ip_address != instance.ip_address || el.port != instance.port);
          /*let mut v = Vec::new();
          for el in front.instances.iter() {
            if el.ip_address != instance.ip_address || el.port != instance.port {
              v.push(el.clone());
            }
          }
          front.instances = v;
          */
        }
      }
      _ => {}
    }
  }

  pub fn generate_commands(&self) -> Vec<Command> {
    let mut v = Vec::new();
    for (app_id, front_list) in self.fronts.iter() {
      for front in front_list {
        v.push(Command::AddHttpFront(HttpFront {
          app_id:     app_id.clone(),
          hostname:   front.hostname.clone(),
          path_begin: front.path_begin.clone(),
        }));
      }
      for (app_id,instance_list) in self.instances.iter() {
        for instance in instance_list {
          v.push(Command::AddInstance(Instance {
            app_id:     app_id.clone(),
            ip_address: instance.ip_address.clone(),
            port:       instance.port.clone(),
          }));
        }
      }
    }

    v
  }
}

impl TlsProxy {
  pub fn new(ip: String, port: u16) -> TlsProxy {
    TlsProxy {
      ip_address: ip,
      port:       port,
      fronts:     HashMap::new(),
      instances:  HashMap::new(),
    }
  }

  pub fn handle_command(&mut self, command: &Command) {
    match command {
      &Command::AddTlsFront(ref front) => {
        let f = TlsProxyFront {
          app_id:      front.app_id.clone(),
          hostname:    front.hostname.clone(),
          path_begin:  front.path_begin.clone(),
          certificate: front.certificate.clone(),
          key:         front.key.clone(),
        };
        if self.fronts.contains_key(&front.app_id) {
          self.fronts.get_mut(&front.app_id).unwrap().push(f);
        } else {
          self.fronts.insert(front.app_id.clone(), vec!(f));
        }
      },
      &Command::RemoveTlsFront(ref front) => {
        self.fronts.remove(&front.app_id);
      },
      &Command::AddInstance(ref instance)  => {
        let inst = HttpProxyInstance {
          ip_address: instance.ip_address.clone(),
          port:       instance.port,
        };
        if self.instances.contains_key(&instance.app_id) {
          self.instances.get_mut(&instance.app_id).unwrap().push(inst);
        } else {
          self.instances.insert(instance.app_id.clone(), vec!(inst));
        }
      },
      &Command::RemoveInstance(ref instance) => {
        if let Some(instance_list) = self.instances.get_mut(&instance.app_id) {
          instance_list.retain(|el| el.ip_address != instance.ip_address || el.port != instance.port);
          /*let mut v = Vec::new();
          for el in instance_list.iter() {
            if el.ip_address != instance.ip_address || el.port != instance.port {
              v.push(el.clone());
            }
          }
          front.instances = v;*/
        }
      }
      _ => {}
    }
  }

  pub fn generate_commands(&self) -> Vec<Command> {
    let mut v = Vec::new();
    for (app_id, front_list) in &self.fronts {
      for front in front_list {
        v.push(Command::AddTlsFront(TlsFront {
          app_id:      app_id.clone(),
          hostname:    front.hostname.clone(),
          path_begin:  front.path_begin.clone(),
          certificate: front.certificate.clone(),
          key:         front.key.clone(),
        }));
      }
    }
    for (app_id, instance_list) in &self.instances {
      for instance in instance_list {
        v.push(Command::AddInstance(Instance {
          app_id:     app_id.clone(),
          ip_address: instance.ip_address.clone(),
          port:       instance.port.clone(),
        }));
      }
    }

    v
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use yxorp::messages::{Command,HttpFront,Instance};

  #[test]
  fn serialize() {
    let mut state = HttpProxy::new(String::from("127.0.0.1"), 80);
    state.handle_command(&Command::AddHttpFront(HttpFront { app_id: String::from("app_1"), hostname: String::from("lolcatho.st:8080"), path_begin: String::from("/") }));
    state.handle_command(&Command::AddHttpFront(HttpFront { app_id: String::from("app_2"), hostname: String::from("test.local"), path_begin: String::from("/abc") }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.1"), port: 1026 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1027 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_2"), ip_address: String::from("192.167.1.2"), port: 1026 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("192.168.1.3"), port: 1027 }));
    state.handle_command(&Command::RemoveInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("192.168.1.3"), port: 1027 }));

    /*
    let encoded = state.encode();
    println!("serialized:\n{}", encoded);

    let new_state: Option<HttpProxy> = decode_str(&encoded);
    println!("deserialized:\n{:?}", new_state);
    assert_eq!(new_state, Some(state));
    */
    //assert!(false);
  }
}
<commit_msg>fix data types<commit_after>use rustc_serialize::{Encodable, Encoder, Decoder};
use std::collections::HashMap;

use yxorp::messages::{Command,HttpFront,TlsFront,Instance};

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct HttpProxyInstance {
  ip_address: String,
  port:       u16,
}

pub type AppId = String;

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct HttpProxyFront {
  app_id:     AppId,
  hostname:   String,
  path_begin: String,
}

#[derive(Debug,Clone,PartialEq,Eq,RustcDecodable, RustcEncodable)]
pub struct HttpProxy {
  ip_address: String,
  port:       u16,
  fronts:     HashMap<AppId, Vec<HttpProxyFront>>,
  instances:  HashMap<AppId, Vec<HttpProxyInstance>>,
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct TlsProxyFront {
  app_id:      AppId,
  hostname:    String,
  path_begin:  String,
  certificate: String,
  key:         String,
  certificate_chain: Vec<String>,
}

#[derive(Debug,Clone,PartialEq,Eq,RustcDecodable, RustcEncodable)]
pub struct TlsProxy {
  ip_address: String,
  port:       u16,
  fronts:     HashMap<AppId, Vec<TlsProxyFront>>,
  instances:  HashMap<AppId, Vec<HttpProxyInstance>>,
}

#[derive(Debug,Clone,PartialEq,Eq)]
pub enum ConfigState {
  Http(HttpProxy),
  Tls(TlsProxy),
}

impl ConfigState {
  pub fn handle_command(&mut self, command: &Command) {
    match *self {
      ConfigState::Http(ref mut state) => state.handle_command(command),
      ConfigState::Tls(ref mut state)  => state.handle_command(command),
    }
  }

  pub fn generate_commands(&self) -> Vec<Command> {
    match *self {
      ConfigState::Http(ref state) => state.generate_commands(),
      ConfigState::Tls(ref state)  => state.generate_commands(),
    }
  }
}

impl Encodable for ConfigState {
  fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
    match *self {
      ConfigState::Http(ref state) => state.encode(e),
      ConfigState::Tls(ref state)  => state.encode(e),
    }
  }
}

impl HttpProxy {
  pub fn new(ip: String, port: u16) -> HttpProxy {
    HttpProxy {
      ip_address: ip,
      port:       port,
      fronts:     HashMap::new(),
      instances:  HashMap::new(),
    }
  }

  pub fn handle_command(&mut self, command: &Command) {
    match command {
      &Command::AddHttpFront(ref front) => {
        let f = HttpProxyFront {
          app_id:     front.app_id.clone(),
          hostname:   front.hostname.clone(),
          path_begin: front.path_begin.clone(),
        };
        if self.fronts.contains_key(&front.app_id) {
          self.fronts.get_mut(&front.app_id).unwrap().push(f);
        } else {
          self.fronts.insert(front.app_id.clone(), vec!(f));
        }
      },
      &Command::RemoveHttpFront(ref front) => {
        if let Some(front_list) = self.fronts.get_mut(&front.app_id) {
          front_list.retain(|el| el.hostname != front.hostname || el.path_begin != front.path_begin);
        }
      },
      &Command::AddInstance(ref instance)  => {
        let inst = HttpProxyInstance {
          ip_address: instance.ip_address.clone(),
          port:       instance.port,
        };
        if self.instances.contains_key(&instance.app_id) {
          self.instances.get_mut(&instance.app_id).unwrap().push(inst);
        } else {
          self.instances.insert(instance.app_id.clone(), vec!(inst));
        }
      },
      &Command::RemoveInstance(ref instance) => {
        if let Some(instance_list) = self.instances.get_mut(&instance.app_id) {
          instance_list.retain(|el| el.ip_address != instance.ip_address || el.port != instance.port);
          /*let mut v = Vec::new();
          for el in front.instances.iter() {
            if el.ip_address != instance.ip_address || el.port != instance.port {
              v.push(el.clone());
            }
          }
          front.instances = v;
          */
        }
      }
      _ => {}
    }
  }

  pub fn generate_commands(&self) -> Vec<Command> {
    let mut v = Vec::new();
    for (app_id, front_list) in self.fronts.iter() {
      for front in front_list {
        v.push(Command::AddHttpFront(HttpFront {
          app_id:     app_id.clone(),
          hostname:   front.hostname.clone(),
          path_begin: front.path_begin.clone(),
        }));
      }
      for (app_id,instance_list) in self.instances.iter() {
        for instance in instance_list {
          v.push(Command::AddInstance(Instance {
            app_id:     app_id.clone(),
            ip_address: instance.ip_address.clone(),
            port:       instance.port.clone(),
          }));
        }
      }
    }

    v
  }
}

impl TlsProxy {
  pub fn new(ip: String, port: u16) -> TlsProxy {
    TlsProxy {
      ip_address: ip,
      port:       port,
      fronts:     HashMap::new(),
      instances:  HashMap::new(),
    }
  }

  pub fn handle_command(&mut self, command: &Command) {
    match command {
      &Command::AddTlsFront(ref front) => {
        let f = TlsProxyFront {
          app_id:      front.app_id.clone(),
          hostname:    front.hostname.clone(),
          path_begin:  front.path_begin.clone(),
          certificate: front.certificate.clone(),
          certificate_chain: front.certificate_chain.clone(),
          key:         front.key.clone(),
        };
        if self.fronts.contains_key(&front.app_id) {
          self.fronts.get_mut(&front.app_id).unwrap().push(f);
        } else {
          self.fronts.insert(front.app_id.clone(), vec!(f));
        }
      },
      &Command::RemoveTlsFront(ref front) => {
        self.fronts.remove(&front.app_id);
      },
      &Command::AddInstance(ref instance)  => {
        let inst = HttpProxyInstance {
          ip_address: instance.ip_address.clone(),
          port:       instance.port,
        };
        if self.instances.contains_key(&instance.app_id) {
          self.instances.get_mut(&instance.app_id).unwrap().push(inst);
        } else {
          self.instances.insert(instance.app_id.clone(), vec!(inst));
        }
      },
      &Command::RemoveInstance(ref instance) => {
        if let Some(instance_list) = self.instances.get_mut(&instance.app_id) {
          instance_list.retain(|el| el.ip_address != instance.ip_address || el.port != instance.port);
          /*let mut v = Vec::new();
          for el in instance_list.iter() {
            if el.ip_address != instance.ip_address || el.port != instance.port {
              v.push(el.clone());
            }
          }
          front.instances = v;*/
        }
      }
      _ => {}
    }
  }

  pub fn generate_commands(&self) -> Vec<Command> {
    let mut v = Vec::new();
    for (app_id, front_list) in &self.fronts {
      for front in front_list {
        v.push(Command::AddTlsFront(TlsFront {
          app_id:      app_id.clone(),
          hostname:    front.hostname.clone(),
          path_begin:  front.path_begin.clone(),
          certificate: front.certificate.clone(),
          certificate_chain: front.certificate_chain.clone(),
          key:         front.key.clone(),
        }));
      }
    }
    for (app_id, instance_list) in &self.instances {
      for instance in instance_list {
        v.push(Command::AddInstance(Instance {
          app_id:     app_id.clone(),
          ip_address: instance.ip_address.clone(),
          port:       instance.port.clone(),
        }));
      }
    }

    v
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use yxorp::messages::{Command,HttpFront,Instance};

  #[test]
  fn serialize() {
    let mut state = HttpProxy::new(String::from("127.0.0.1"), 80);
    state.handle_command(&Command::AddHttpFront(HttpFront { app_id: String::from("app_1"), hostname: String::from("lolcatho.st:8080"), path_begin: String::from("/") }));
    state.handle_command(&Command::AddHttpFront(HttpFront { app_id: String::from("app_2"), hostname: String::from("test.local"), path_begin: String::from("/abc") }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.1"), port: 1026 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("127.0.0.2"), port: 1027 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_2"), ip_address: String::from("192.167.1.2"), port: 1026 }));
    state.handle_command(&Command::AddInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("192.168.1.3"), port: 1027 }));
    state.handle_command(&Command::RemoveInstance(Instance { app_id: String::from("app_1"), ip_address: String::from("192.168.1.3"), port: 1027 }));

    /*
    let encoded = state.encode();
    println!("serialized:\n{}", encoded);

    let new_state: Option<HttpProxy> = decode_str(&encoded);
    println!("deserialized:\n{:?}", new_state);
    assert_eq!(new_state, Some(state));
    */
    //assert!(false);
  }
}
<|endoftext|>


<commit_before>//! Bindings to libgit2's raw git_strarray type

use std::ops::Deref;

use oid::Oid;
use raw;
use util::Binding;
use std::slice;

/// An oid array structure used by libgit2
///
/// Some apis return arrays of oids which originate from libgit2. This
/// wrapper type behaves a little like `Vec<&Oid>` but does so without copying
/// the underlying Oids until necessary.
pub struct OidArray {
    raw: raw::git_oidarray,
}

impl OidArray {
    /// Returns None if i is out of bounds.
    pub fn get(&self, i: usize) -> Option<Oid> {
        if i < self.raw.count as usize {
            Some(self[i])
        } else {
            None
        }
    }
}

impl Deref for OidArray {
    type Target = [Oid];

    fn deref(&self) -> &[Oid] {
        unsafe {
            slice::from_raw_parts(self.raw.ids as *const Oid, self.raw.count as usize)
        }
    }
}

impl Binding for OidArray {
    type Raw = raw::git_oidarray;
    unsafe fn from_raw(raw: raw::git_oidarray) -> OidArray {
        OidArray { raw: raw }
    }
    fn raw(&self) -> raw::git_oidarray { self.raw }
}

impl Drop for OidArray {
    fn drop(&mut self) {
        unsafe { raw::git_oidarray_free(&mut self.raw) }
    }
}
<commit_msg>add debug_assert to check repr of Oid and git_oid are the same<commit_after>//! Bindings to libgit2's raw git_strarray type

use std::ops::Deref;

use oid::Oid;
use raw;
use util::Binding;
use std::slice;
use std::mem;

/// An oid array structure used by libgit2
///
/// Some apis return arrays of oids which originate from libgit2. This
/// wrapper type behaves a little like `Vec<&Oid>` but does so without copying
/// the underlying Oids until necessary.
pub struct OidArray {
    raw: raw::git_oidarray,
}

impl OidArray {
    /// Returns None if i is out of bounds.
    pub fn get(&self, i: usize) -> Option<Oid> {
        if i < self.raw.count as usize {
            Some(self[i])
        } else {
            None
        }
    }
}

impl Deref for OidArray {
    type Target = [Oid];

    fn deref(&self) -> &[Oid] {
        unsafe {
            debug_assert_eq!(mem::size_of::<Oid>(), mem::size_of_val(&*self.raw.ids));

            slice::from_raw_parts(self.raw.ids as *const Oid, self.raw.count as usize)
        }
    }
}

impl Binding for OidArray {
    type Raw = raw::git_oidarray;
    unsafe fn from_raw(raw: raw::git_oidarray) -> OidArray {
        OidArray { raw: raw }
    }
    fn raw(&self) -> raw::git_oidarray { self.raw }
}

impl Drop for OidArray {
    fn drop(&mut self) {
        unsafe { raw::git_oidarray_free(&mut self.raw) }
    }
}
<|endoftext|>


<commit_before>/* kernel::sgash.rs */
#[allow(unused_imports)];
use core::*;
use core::str::*;
use core::option::{Some, Option, None};
use core::iter::Iterator;
use kernel::*;
use super::super::platform::*;
use kernel::memory::Allocator;

// Used to store character into QEMU
pub fn putchar(key: char) {
    unsafe {
        /*
        * We need to include a blank asm call to prevent rustc
        * from optimizing this part out
        */
        asm!("");
        io::write_char(key, io::UART0);
    }
}

fn putstr(msg: &str) {
    for c in slice::iter(as_bytes(msg)) {
        putchar(*c as char);
    }
}

pub unsafe fn drawstr(msg: &str) {
    // See starting code to change color of print out
    for c in slice::iter(as_bytes(msg)) {
        drawchar(*c as char);
    }
}

// Draws character onto QEMU screen
unsafe fn drawchar(x: char)
{
    io::restore();
    if x == '\n' {
io::CURSOR_Y += io::CURSOR_HEIGHT;
io::CURSOR_X = 0u32;
    } else {
io::draw_char(x);
io::CURSOR_X += io::CURSOR_WIDTH;
    }
    io::backup();
    io::draw_cursor();
}

unsafe fn backspace()
{
    io::restore();
    if (io::CURSOR_X >= io::CURSOR_WIDTH) {
io::CURSOR_X -= io::CURSOR_WIDTH;
io::draw_char(' ');
    }
    io::backup();
    io::draw_cursor();
}

// Used to get keystroke and print onscreen
pub unsafe fn parsekey(x: char) {
    let x = x as u8;
    match x {
        13  =>  {
            // Activate/parse commands here
            //parse();
            //echo();
            prompt(false);
        }
        127 =>  {
            putchar('');
            putchar(' ');
            putchar('');
            backspace();
        }
        _   =>  {
            if (buffer.add_char(x)) {
                putchar(x as char);
                drawchar(x as char);
            }
        }
    }
}

pub unsafe fn init() {
    buffer = cstr::new(256);
    screen();
    // First prompt does draw, but out of bounds?
    prompt(true);
}

/****************** Added Code ***************/
pub static mut buffer: cstr = cstr {
    pointer: 0 as *mut u8,
    index_pointer: 0,
    max: 0
};

// Problem 4: echo input on second line
unsafe fn echo() {
    // Iterate through buffer and print
    putstr(&"\n");
    drawstr(&"\n");
    let mut i: uint = 0;
    while i < buffer.len(){
        let current_char: char = buffer.get_char(i);

        // Miss first char on first echo, and occassionally gets wrong char
        // This is more likely an issue with the string implementation itself
        putchar(current_char);

        drawchar(current_char);       // Hangs here
        i += 1;
    }
    buffer.reset();
    putstr(&"\n");
    drawstr(&"\n");
}

unsafe fn prompt(startup: bool) {
    putstr(&"\nsgash > ");
    if !startup {
        drawstr(&"\nsgash > ");
    }
    buffer.reset();
}

// Problem 5: Recognize shell commands
// Issue here, only ls recognized
unsafe fn parse() {
    if (buffer.streq(&"ls")) {
        putstr( &"\na\tb") ;
        drawstr( &"\na    b") ;
    };
    if buffer.streq(&"cat a") {
        putstr(&"\na is here");
        putstr(&"\na is here");
    }
    // Separates what's in buffer by spliting spaces
    match buffer.getarg(' ', 0) {
        Some(y)        => {
        if(y.streq(&"cat")) {
            match buffer.getarg(' ', 1) {
            Some(x)        => {
                if(x.streq(&"a")) {
                putstr( &"\nHowdy!");
                drawstr( &"\nHowdy!");
                }
                if(x.streq(&"b")) {
                putstr( &"\nworld!");
                drawstr( &"\nworld!");
                }
            }
            None        => { }
            };
        }
        if(y.streq(&"open")) {
            putstr(&"\nTEST YO");
            drawstr(&"\nTEST YO");
        }
        if(y.streq(&"echo")) {
            putstr(&"\necho");
            drawstr(&"\necho");
        }
        if(y.streq(&"ls")) {
            putstr(&"\nhelp");
            drawstr(&"\nhelp");
        }
        if(y.streq(&"cd")) {
            putstr(&"\ncd");
            drawstr(&"\ncd");
        }
        if(y.streq(&"rm")) {
            putstr(&"\nrm");
            drawstr(&"\nrm");
        }
        if(y.streq(&"mkdir")) {
            putstr(&"\nmkdir");
            drawstr(&"\nmkdir");
        }
        if(y.streq(&"pwd")) {
            putstr(&"\npwd");
            drawstr(&"\npwd");
        }
        if(y.streq(&"wr")) {
            putstr(&"\nwr");
            drawstr(&"\nwr");
        }

        }
        None        => {
            putstr(&"Recognize any command");
            drawstr(&"Recognize any command");
        }
    };
    buffer.reset();
}

/* CString */
struct cstr {
    pointer: *mut u8,       // Starting address
    index_pointer: uint,    // Address of i
    max: uint               // Maximum end address
}

impl cstr {
    pub unsafe fn new(size: uint) -> cstr {
        // Sometimes this doesn't allocate enough memory and gets stuck...
        let (addr_offset,mem_size) = heap.alloc(size);
        let this = cstr {
            pointer:            addr_offset,
            index_pointer:      0,
            max:                mem_size
        };
        // String requires null terminator
        *(((this.pointer as uint)+this.index_pointer) as *mut char) = '\0';
        this
    }

#[allow(dead_code)]
    unsafe fn from_str(s: &str) -> cstr {
        let mut this = cstr::new(256);
        for c in slice::iter(as_bytes(s)) {
            this.add_char(*c);
        };
        this
    }

#[allow(dead_code)]
    fn len(&self) -> uint { self.index_pointer }

    // HELP THIS DOESN'T WORK THERE IS NO GARBAGE COLLECTION!!!
    // -- TODO: exchange_malloc, exchange_free
#[allow(dead_code)]
    unsafe fn destroy(&self) { heap.free(self.pointer); }

    unsafe fn add_char(&mut self, x: u8) -> bool{
        if (self.index_pointer == self.max) { return false; }
        *(((self.pointer as uint)+self.index_pointer) as *mut u8) = x;
        self.index_pointer += 1;
        *(((self.pointer as uint)+self.index_pointer) as *mut char) = '\0';
        true
    }

    // Used for echo function
    unsafe fn get_char(&mut self, index: uint) -> char {
        if self.index_pointer == 0 {
            return (0 as u8) as char;
        }
        return *(((self.pointer as uint)+index) as *mut char);
    }

    unsafe fn delete_char(&mut self) -> bool {
        if (self.index_pointer == 0) { return false; }
        self.index_pointer -= 1;
        *(((self.pointer as uint)+self.index_pointer) as *mut char) = '\0';
        true
    }

    unsafe fn reset(&mut self) {
        self.index_pointer = 0;
        *(self.pointer as *mut char) = '\0';
    }

#[allow(dead_code)]
    unsafe fn eq(&self, other: &cstr) -> bool {
        if (self.len() != other.len()) { return false; }
        else {
            let mut x = 0;
            let mut selfp: uint = self.pointer as uint;
            let mut otherp: uint = other.pointer as uint;
            while x < self.len() {
                if (*(selfp as *char) != *(otherp as *char)) { return false; }
                selfp += 1;
                otherp += 1;
                x += 1;
            }
            true
        }
    }

    unsafe fn streq(&self, other: &str) -> bool {
        let mut selfp: uint = self.pointer as uint;
        for c in slice::iter(as_bytes(other)) {
            if( *c != *(selfp as *u8) ) { return false; }
            selfp += 1;
        };
        *(selfp as *char) == '\0'
    }

    unsafe fn getarg(&self, delim: char, mut k: uint) -> Option<cstr> {
        let mut ind: uint = 0;
        let mut found = k == 0;
        let mut selfp: uint = self.pointer as uint;
        let mut s = cstr::new(256);
        loop {
            if (*(selfp as *char) == '\0') {
                // End of string
                if (found) { return Some(s); }
                else { return None; }
            };
            if (*(selfp as *u8) == delim as u8) {
                if (found) { return Some(s); }
                k -= 1;
            };
            if (found) {
                s.add_char(*(selfp as *u8));
            };
            found = k == 0;
            selfp += 1;
            ind += 1;
            if (ind == self.max) {
                putstr(&"\nSomething broke!");
                return None;
            }
        }
    }

#[allow(dead_code)]
    unsafe fn split(&self, delim: char) -> (cstr, cstr) {
        let mut selfp: uint = self.pointer as uint;
        let mut beg = cstr::new(256);
        let mut end = cstr::new(256);
        let mut found = false;
        loop {
            if (*(selfp as *char) == '\0') {
                return (beg, end);
            }
            else if (*(selfp as *u8) == delim as u8) {
                found = true;
            }
            else if (!found) {
                beg.add_char(*(selfp as *u8));
            }
            else if (found) {
                end.add_char(*(selfp as *u8));
            };
            selfp += 1;
        }
    }

}

// No real purpose beside printing on bash
fn screen() {
    putstr(&"\n ");
    putstr(&"\n ");
    putstr(&"\n 7=..~$=..:7 ");
    putstr(&"\n +$: =$$$+$$$?$$$+ ,7? ");
    putstr(&"\n $$$$$$$$$$$$$$$$$$Z$$ ");
    putstr(&"\n 7$$$$$$$$$$$$. .Z$$$$$Z$$$$$$ ");
    putstr(&"\n ~..7$$Z$$$$$7+7$+.?Z7=7$$Z$$Z$$$..: ");
    putstr(&"\n ~$$$$$$$$7: :ZZZ, :7ZZZZ$$$$= ");
    putstr(&"\n Z$$$$$? .+ZZZZ$$ ");
    putstr(&"\n +$ZZ$$$Z7 7ZZZ$Z$$I. ");
    putstr(&"\n $$$$ZZZZZZZZZZZZZZZZZZZZZZZZI, ,ZZZ$$Z ");
    putstr(&"\n :+$$$$ZZZZZZZZZZZZZZZZZZZZZZZZZZZ= $ZZ$$+~, ");
    putstr(&"\n ?$Z$$$$ZZZZZZZZZZZZZZZZZZZZZZZZZZZZI 7ZZZ$ZZI ");
    putstr(&"\n =Z$$+7Z$$7ZZZZZZZZ$$$$$$$ZZZZZZZZZZ ~Z$?$ZZ? ");
    putstr(&"\n :$Z$Z...$Z $ZZZZZZZ~ ~ZZZZZZZZ,.ZZ...Z$Z$~ ");
    putstr(&"\n 7ZZZZZI$ZZ $ZZZZZZZ~ =ZZZZZZZ7..ZZ$?$ZZZZ$ ");
    putstr(&"\n ZZZZ$: $ZZZZZZZZZZZZZZZZZZZZZZ= ~$ZZZ$: ");
    putstr(&"\n 7Z$ZZ$, $ZZZZZZZZZZZZZZZZZZZZ7 ZZZ$Z$ ");
    putstr(&"\n =ZZZZZZ, $ZZZZZZZZZZZZZZZZZZZZZZ, ZZZ$ZZ+ ");
    putstr(&"\n ,ZZZZ, $ZZZZZZZ: =ZZZZZZZZZ ZZZZZ$: ");
    putstr(&"\n =$ZZZZ+ ZZZZZZZZ~ ZZZZZZZZ~ =ZZZZZZZI ");
    putstr(&"\n $ZZ$ZZZ$$Z$$ZZZZZZZZZ$$$$ IZZZZZZZZZ$ZZZZZZZZZ$ ");
    putstr(&"\n :ZZZZZZZZZZZZZZZZZZZZZZ ~ZZZZZZZZZZZZZZZZZ~ ");
    putstr(&"\n ,Z$$ZZZZZZZZZZZZZZZZZZZZ ZZZZZZZZZZZZZZZZZZ~ ");
    putstr(&"\n =$ZZZZZZZZZZZZZZZZZZZZZZ $ZZZZZZZZZZZZZZZ$+ ");
    putstr(&"\n IZZZZZ:. . ,ZZZZZ$ ");
    putstr(&"\n ~$ZZZZZZZZZZZ ZZZZ$ZZZZZZZ+ ");
    putstr(&"\n Z$ZZZ. ,Z~ =Z:.,ZZZ$Z ");
    putstr(&"\n ,ZZZZZ..~Z$. .7Z:..ZZZZZ: ");
    putstr(&"\n ~7+:$ZZZZZZZZI=:. .,=IZZZZZZZ$Z:=7= ");
    putstr(&"\n $$ZZZZZZZZZZZZZZZZZZZZZZ$ZZZZ ");
    putstr(&"\n ==..$ZZZ$ZZZZZZZZZZZ$ZZZZ .~+ ");
    putstr(&"\n I$?.?ZZZ$ZZZ$ZZZI =$7 ");
    putstr(&"\n $7..I$7..I$, ");
    putstr(&"\n");
    putstr(&"\n _ _ _ _ ");
    putstr(&"\n| | (_) | | | | ");
    putstr(&"\n| | ____ ___ ____ _____| |_____ ____ ____ _____| | ");
    putstr(&"\n| |/ ___) _ \\| _ \\ | _ _) ___ |/ ___) _ \\| ___ | | ");
    putstr(&"\n| | | | |_| | | | | | | \\ \\| ____| | | | | | ____| | ");
    putstr(&"\n|_|_| \\____/|_| |_| |_| \\_\\_____)_| |_| |_|_____)__)\n\n");
}<commit_msg>Echo more or less works, but prompting not totally correct<commit_after>/* kernel::sgash.rs */
#[allow(unused_imports)];
use core::*;
use core::str::*;
use core::option::{Some, Option, None};
use core::iter::Iterator;
use kernel::*;
use super::super::platform::*;
use kernel::memory::Allocator;

// Used to store character into QEMU
pub fn putchar(key: char) {
    unsafe {
        /*
        * We need to include a blank asm call to prevent rustc
        * from optimizing this part out
        */
        asm!("");
        io::write_char(key, io::UART0);
    }
}

fn putstr(msg: &str) {
    for c in slice::iter(as_bytes(msg)) {
        putchar(*c as char);
    }
}

pub unsafe fn drawstr(msg: &str) {
    // See starting code to change color of print out
    for c in slice::iter(as_bytes(msg)) {
        drawchar(*c as char);
    }
}

// Draws character onto QEMU screen
unsafe fn drawchar(x: char)
{
    io::restore();
    if x == '\n' {
io::CURSOR_Y += io::CURSOR_HEIGHT;
io::CURSOR_X = 0u32;
    } else {
io::draw_char(x);
io::CURSOR_X += io::CURSOR_WIDTH;
    }
    io::backup();
    io::draw_cursor();
}

unsafe fn backspace()
{
    io::restore();
    if (io::CURSOR_X >= io::CURSOR_WIDTH) {
io::CURSOR_X -= io::CURSOR_WIDTH;
io::draw_char(' ');
    }
    io::backup();
    io::draw_cursor();
}

// Used to get keystroke and print onscreen
pub unsafe fn parsekey(x: char) {
    let x = x as u8;
    match x {
        13  =>  {
            // Activate/parse commands here
            parse();
            //echo();
            prompt(false);
        }
        127 =>  {
            putchar('');
            putchar(' ');
            putchar('');
            backspace();
        }
        _   =>  {
            if (buffer.add_char(x)) {
                putchar(x as char);
                drawchar(x as char);
            }
        }
    }
}

pub unsafe fn init() {
    buffer = cstr::new(256);
    screen();
    // First prompt does draw, but out of bounds?
    prompt(true);
}

/****************** Added Code ***************/
pub static mut buffer: cstr = cstr {
    pointer: 0 as *mut u8,
    index_pointer: 0,
    max: 0
};

// Problem 4: echo input on second line
unsafe fn echo() {
    putstr(&"\n");
    drawstr(&"\n");
    let mut i: uint = 0;
    while i < buffer.len(){
        let current_char: char = buffer.get_char(i);

        // Occassionally gets wrong char, probably something to do with the cstr implementation
        putchar(current_char);
        drawchar(current_char);       // Hangs without the first sgash> prompt
        i += 1;
    }
    buffer.reset();
}

unsafe fn prompt(startup: bool) {
    putstr(&"\nsgash > ");
    if !startup {
        drawstr(&"\nsgash > ");
    } else {
        // Technically it's there, but it's not visible
        // Unlikely color issue, maybe something with CRUSOR?
        drawstr(&"\nstart >");
    }
    buffer.reset();
}

// Problem 5: Recognize shell commands
// Issue here, only ls recognized
unsafe fn parse() {
    if (buffer.streq(&"ls")) {
        putstr( &"\na\tb") ;
        drawstr( &"\na    b") ;
    };
    if buffer.streq(&"cat a") {
        putstr(&"\na is here");
        putstr(&"\na is here");
    }
    // Separates what's in buffer by spliting spaces
    match buffer.getarg(' ', 0) {
        Some(y)        => {
        if(y.streq(&"cat")) {
            match buffer.getarg(' ', 1) {
            Some(x)        => {
                if(x.streq(&"a")) {
                putstr( &"\nHowdy!");
                drawstr( &"\nHowdy!");
                }
                if(x.streq(&"b")) {
                putstr( &"\nworld!");
                drawstr( &"\nworld!");
                }
            }
            None        => { }
            };
        }
        if(y.streq(&"open")) {
            putstr(&"\nTEST YO");
            drawstr(&"\nTEST YO");
        }
        if(y.streq(&"echo")) {
            putstr(&"\necho");
            drawstr(&"\necho");
        }
        if(y.streq(&"ls")) {
            putstr(&"\nhelp");
            drawstr(&"\nhelp");
        }
        if(y.streq(&"cd")) {
            putstr(&"\ncd");
            drawstr(&"\ncd");
        }
        if(y.streq(&"rm")) {
            putstr(&"\nrm");
            drawstr(&"\nrm");
        }
        if(y.streq(&"mkdir")) {
            putstr(&"\nmkdir");
            drawstr(&"\nmkdir");
        }
        if(y.streq(&"pwd")) {
            putstr(&"\npwd");
            drawstr(&"\npwd");
        }
        if(y.streq(&"wr")) {
            putstr(&"\nwr");
            drawstr(&"\nwr");
        }

        }
        None        => {
            putstr(&"Recognize any command");
            drawstr(&"Recognize any command");
        }
    };
    buffer.reset();
}

/* CString */
struct cstr {
    pointer: *mut u8,       // Starting address
    index_pointer: uint,    // Address of i
    max: uint               // Maximum end address
}

impl cstr {
    pub unsafe fn new(size: uint) -> cstr {
        // Sometimes this doesn't allocate enough memory and gets stuck...
        let (addr_offset,mem_size) = heap.alloc(size);
        let this = cstr {
            pointer:            addr_offset,
            index_pointer:      0,
            max:                mem_size
        };
        // String requires null terminator
        *(((this.pointer as uint)+this.index_pointer) as *mut char) = '\0';
        this
    }

#[allow(dead_code)]
    unsafe fn from_str(s: &str) -> cstr {
        let mut this = cstr::new(256);
        for c in slice::iter(as_bytes(s)) {
            this.add_char(*c);
        };
        this
    }

#[allow(dead_code)]
    fn len(&self) -> uint { self.index_pointer }

    // HELP THIS DOESN'T WORK THERE IS NO GARBAGE COLLECTION!!!
    // -- TODO: exchange_malloc, exchange_free
#[allow(dead_code)]
    unsafe fn destroy(&self) { heap.free(self.pointer); }

    unsafe fn add_char(&mut self, x: u8) -> bool{
        if (self.index_pointer == self.max) { return false; }
        *(((self.pointer as uint)+self.index_pointer) as *mut u8) = x;
        self.index_pointer += 1;
        *(((self.pointer as uint)+self.index_pointer) as *mut char) = '\0';
        true
    }

    // Used for echo function
    unsafe fn get_char(&mut self, index: uint) -> char {
        if self.index_pointer == 0 {
            return (0 as u8) as char;
        }
        return *(((self.pointer as uint)+index) as *mut char);
    }

    unsafe fn delete_char(&mut self) -> bool {
        if (self.index_pointer == 0) { return false; }
        self.index_pointer -= 1;
        *(((self.pointer as uint)+self.index_pointer) as *mut char) = '\0';
        true
    }

    unsafe fn reset(&mut self) {
        self.index_pointer = 0;
        *(self.pointer as *mut char) = '\0';
    }

#[allow(dead_code)]
    unsafe fn eq(&self, other: &cstr) -> bool {
        if (self.len() != other.len()) { return false; }
        else {
            let mut x = 0;
            let mut selfp: uint = self.pointer as uint;
            let mut otherp: uint = other.pointer as uint;
            while x < self.len() {
                if (*(selfp as *char) != *(otherp as *char)) { return false; }
                selfp += 1;
                otherp += 1;
                x += 1;
            }
            true
        }
    }

    unsafe fn streq(&self, other: &str) -> bool {
        let mut selfp: uint = self.pointer as uint;
        for c in slice::iter(as_bytes(other)) {
            if( *c != *(selfp as *u8) ) { return false; }
            selfp += 1;
        };
        *(selfp as *char) == '\0'
    }

    unsafe fn getarg(&self, delim: char, mut k: uint) -> Option<cstr> {
        let mut ind: uint = 0;
        let mut found = k == 0;
        let mut selfp: uint = self.pointer as uint;
        let mut s = cstr::new(256);
        loop {
            if (*(selfp as *char) == '\0') {
                // End of string
                if (found) { return Some(s); }
                else { return None; }
            };
            if (*(selfp as *u8) == delim as u8) {
                if (found) { return Some(s); }
                k -= 1;
            };
            if (found) {
                s.add_char(*(selfp as *u8));
            };
            found = k == 0;
            selfp += 1;
            ind += 1;
            if (ind == self.max) {
                putstr(&"\nSomething broke!");
                return None;
            }
        }
    }

#[allow(dead_code)]
    unsafe fn split(&self, delim: char) -> (cstr, cstr) {
        let mut selfp: uint = self.pointer as uint;
        let mut beg = cstr::new(256);
        let mut end = cstr::new(256);
        let mut found = false;
        loop {
            if (*(selfp as *char) == '\0') {
                return (beg, end);
            }
            else if (*(selfp as *u8) == delim as u8) {
                found = true;
            }
            else if (!found) {
                beg.add_char(*(selfp as *u8));
            }
            else if (found) {
                end.add_char(*(selfp as *u8));
            };
            selfp += 1;
        }
    }

}

// No real purpose beside printing on bash
fn screen() {
    putstr(&"\n ");
    putstr(&"\n ");
    putstr(&"\n 7=..~$=..:7 ");
    putstr(&"\n +$: =$$$+$$$?$$$+ ,7? ");
    putstr(&"\n $$$$$$$$$$$$$$$$$$Z$$ ");
    putstr(&"\n 7$$$$$$$$$$$$. .Z$$$$$Z$$$$$$ ");
    putstr(&"\n ~..7$$Z$$$$$7+7$+.?Z7=7$$Z$$Z$$$..: ");
    putstr(&"\n ~$$$$$$$$7: :ZZZ, :7ZZZZ$$$$= ");
    putstr(&"\n Z$$$$$? .+ZZZZ$$ ");
    putstr(&"\n +$ZZ$$$Z7 7ZZZ$Z$$I. ");
    putstr(&"\n $$$$ZZZZZZZZZZZZZZZZZZZZZZZZI, ,ZZZ$$Z ");
    putstr(&"\n :+$$$$ZZZZZZZZZZZZZZZZZZZZZZZZZZZ= $ZZ$$+~, ");
    putstr(&"\n ?$Z$$$$ZZZZZZZZZZZZZZZZZZZZZZZZZZZZI 7ZZZ$ZZI ");
    putstr(&"\n =Z$$+7Z$$7ZZZZZZZZ$$$$$$$ZZZZZZZZZZ ~Z$?$ZZ? ");
    putstr(&"\n :$Z$Z...$Z $ZZZZZZZ~ ~ZZZZZZZZ,.ZZ...Z$Z$~ ");
    putstr(&"\n 7ZZZZZI$ZZ $ZZZZZZZ~ =ZZZZZZZ7..ZZ$?$ZZZZ$ ");
    putstr(&"\n ZZZZ$: $ZZZZZZZZZZZZZZZZZZZZZZ= ~$ZZZ$: ");
    putstr(&"\n 7Z$ZZ$, $ZZZZZZZZZZZZZZZZZZZZ7 ZZZ$Z$ ");
    putstr(&"\n =ZZZZZZ, $ZZZZZZZZZZZZZZZZZZZZZZ, ZZZ$ZZ+ ");
    putstr(&"\n ,ZZZZ, $ZZZZZZZ: =ZZZZZZZZZ ZZZZZ$: ");
    putstr(&"\n =$ZZZZ+ ZZZZZZZZ~ ZZZZZZZZ~ =ZZZZZZZI ");
    putstr(&"\n $ZZ$ZZZ$$Z$$ZZZZZZZZZ$$$$ IZZZZZZZZZ$ZZZZZZZZZ$ ");
    putstr(&"\n :ZZZZZZZZZZZZZZZZZZZZZZ ~ZZZZZZZZZZZZZZZZZ~ ");
    putstr(&"\n ,Z$$ZZZZZZZZZZZZZZZZZZZZ ZZZZZZZZZZZZZZZZZZ~ ");
    putstr(&"\n =$ZZZZZZZZZZZZZZZZZZZZZZ $ZZZZZZZZZZZZZZZ$+ ");
    putstr(&"\n IZZZZZ:. . ,ZZZZZ$ ");
    putstr(&"\n ~$ZZZZZZZZZZZ ZZZZ$ZZZZZZZ+ ");
    putstr(&"\n Z$ZZZ. ,Z~ =Z:.,ZZZ$Z ");
    putstr(&"\n ,ZZZZZ..~Z$. .7Z:..ZZZZZ: ");
    putstr(&"\n ~7+:$ZZZZZZZZI=:. .,=IZZZZZZZ$Z:=7= ");
    putstr(&"\n $$ZZZZZZZZZZZZZZZZZZZZZZ$ZZZZ ");
    putstr(&"\n ==..$ZZZ$ZZZZZZZZZZZ$ZZZZ .~+ ");
    putstr(&"\n I$?.?ZZZ$ZZZ$ZZZI =$7 ");
    putstr(&"\n $7..I$7..I$, ");
    putstr(&"\n");
    putstr(&"\n _ _ _ _ ");
    putstr(&"\n| | (_) | | | | ");
    putstr(&"\n| | ____ ___ ____ _____| |_____ ____ ____ _____| | ");
    putstr(&"\n| |/ ___) _ \\| _ \\ | _ _) ___ |/ ___) _ \\| ___ | | ");
    putstr(&"\n| | | | |_| | | | | | | \\ \\| ____| | | | | | ____| | ");
    putstr(&"\n|_|_| \\____/|_| |_| |_| \\_\\_____)_| |_| |_|_____)__)\n\n");
}<|endoftext|>


<commit_before>#![allow(dead_code, non_camel_case_types)]
#[macro_use]
extern crate derive_more;

#[derive(From, Not, Add, AddAssign, Mul, FromStr, Display, Index)]
struct Wrapped<T: Clone>(T);

#[derive(From, Not, Add, AddAssign, Mul)]
struct WrappedDouble<T: Clone, U: Clone>(T, U);

#[derive(From, Not, Add, AddAssign, Mul, FromStr, Display, Index)]
struct Struct<T: Clone> {
    t: T,
}

#[derive(From, Not, Add, AddAssign, Mul)]
struct DoubleStruct<T: Clone, U: Clone> {
    t: T,
    u: U,
}

#[derive(From, Not, Add)]
enum TupleEnum<T: Clone, U: Clone> {
    Tuple(T),
    DoubleTuple(T, U),
}

#[derive(From, Not, Add)]
enum StructEnum<T: Clone, U: Clone> {
    Struct { t: T },
    DoubleStruct { t: T, u: U },
}
<commit_msg>Tests: Test generics for IndexMut and Constructor<commit_after>#![allow(dead_code, non_camel_case_types)]
#[macro_use]
extern crate derive_more;

#[derive(From, FromStr, Display, Index, Not, Add, Mul, IndexMut, AddAssign, Constructor)]
struct Wrapped<T: Clone>(T);

#[derive(From, Not, Add, Mul, AddAssign, Constructor)]
struct WrappedDouble<T: Clone, U: Clone>(T, U);

#[derive(From, FromStr, Display, Index, Not, Add, Mul, IndexMut, AddAssign, Constructor)]
struct Struct<T: Clone> {
    t: T,
}

#[derive(From, Not, Add, Mul, AddAssign, Constructor)]
struct DoubleStruct<T: Clone, U: Clone> {
    t: T,
    u: U,
}

#[derive(From, Not, Add)]
enum TupleEnum<T: Clone, U: Clone> {
    Tuple(T),
    DoubleTuple(T, U),
}

#[derive(From, Not, Add)]
enum StructEnum<T: Clone, U: Clone> {
    Struct { t: T },
    DoubleStruct { t: T, u: U },
}
<|endoftext|>


<commit_before>use Result;
use point::Error;

/// The ASPRS classification table.
///
/// Classifications can be created from u8s and converted back into them:
///
/// ```
/// use las::point::Classification;
/// let classification = Classification::new(2).unwrap();
/// assert_eq!(Classification::Ground, classification);
/// assert_eq!(2, u8::from(classification));
/// ```
///
/// We make one modification to this table: we remove `OverlapPoints`, code 12. Las 1.4 added the
/// extended point formats, which include an overlap bit. The overlap bit is intended to allow a
/// point to both be an overlap point and contain some other classification.
///
/// Here's how we deal with that change:
///
/// - If the point format doesn't support the overlap bit, the classification is overwritten with
/// the code for overlap points (12). On ingest, points with an overlap classification are given
/// the `Unclassified` code and `Point::is_overlap` is set to `true`.
/// - If the point format does support the overlap bit, that is preferred.
///
/// Because of this change, trying to create a classification with code 12 is an error:
///
/// ```
/// use las::point::Classification;
/// assert!(Classification::new(12).is_err());
/// ```
#[derive(Clone, Copy, Debug, PartialEq)]
#[allow(missing_docs)]
pub enum Classification {
    CreatedNeverClassified,
    Unclassified,
    Ground,
    LowVegetation,
    MediumVegetation,
    HighVegetation,
    Building,
    LowPoint,
    ModelKeyPoint,
    Water,
    Rail,
    RoadSurface,
    WireGuard,
    WireConductor,
    TransmissionTower,
    WireStructureConnector,
    BridgeDeck,
    HighNoise,
    Reserved(u8),
    UserDefinable(u8),
}

impl Classification {
    /// Creates a new classification.
    ///
    /// Throws an error if the classification is 12 (overlap).
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Classification;
    /// assert_eq!(Classification::Ground, Classification::new(2).unwrap());
    /// assert!(Classification::new(12).is_err());
    /// ```
    pub fn new(n: u8) -> Result<Classification> {
        Ok(match n {
            0 => Classification::CreatedNeverClassified,
            1 => Classification::Unclassified,
            2 => Classification::Ground,
            3 => Classification::LowVegetation,
            4 => Classification::MediumVegetation,
            5 => Classification::HighVegetation,
            6 => Classification::Building,
            7 => Classification::LowPoint,
            8 => Classification::ModelKeyPoint,
            9 => Classification::Water,
            10 => Classification::Rail,
            11 => Classification::RoadSurface,
            12 => return Err(Error::OverlapClassification.into()),
            13 => Classification::WireGuard,
            14 => Classification::WireConductor,
            15 => Classification::TransmissionTower,
            16 => Classification::WireStructureConnector,
            17 => Classification::BridgeDeck,
            18 => Classification::HighNoise,
            19...64 => Classification::Reserved(n),
            64...255 => Classification::UserDefinable(n),
            _ => unreachable!(),
        })
    }
}

impl From<Classification> for u8 {
    fn from(classification: Classification) -> u8 {
        match classification {
            Classification::CreatedNeverClassified => 0,
            Classification::Unclassified => 1,
            Classification::Ground => 2,
            Classification::LowVegetation => 3,
            Classification::MediumVegetation => 4,
            Classification::HighVegetation => 5,
            Classification::Building => 6,
            Classification::LowPoint => 7,
            Classification::ModelKeyPoint => 8,
            Classification::Water => 9,
            Classification::Rail => 10,
            Classification::RoadSurface => 11,
            Classification::WireGuard => 13,
            Classification::WireConductor => 14,
            Classification::TransmissionTower => 15,
            Classification::WireStructureConnector => 16,
            Classification::BridgeDeck => 17,
            Classification::HighNoise => 18,
            Classification::Reserved(n) |
            Classification::UserDefinable(n) => n,
        }
    }
}

impl Default for Classification {
    fn default() -> Classification {
        Classification::CreatedNeverClassified
    }
}
<commit_msg>Match ranges are inclusive<commit_after>use Result;
use point::Error;

/// The ASPRS classification table.
///
/// Classifications can be created from u8s and converted back into them:
///
/// ```
/// use las::point::Classification;
/// let classification = Classification::new(2).unwrap();
/// assert_eq!(Classification::Ground, classification);
/// assert_eq!(2, u8::from(classification));
/// ```
///
/// We make one modification to this table: we remove `OverlapPoints`, code 12. Las 1.4 added the
/// extended point formats, which include an overlap bit. The overlap bit is intended to allow a
/// point to both be an overlap point and contain some other classification.
///
/// Here's how we deal with that change:
///
/// - If the point format doesn't support the overlap bit, the classification is overwritten with
/// the code for overlap points (12). On ingest, points with an overlap classification are given
/// the `Unclassified` code and `Point::is_overlap` is set to `true`.
/// - If the point format does support the overlap bit, that is preferred.
///
/// Because of this change, trying to create a classification with code 12 is an error:
///
/// ```
/// use las::point::Classification;
/// assert!(Classification::new(12).is_err());
/// ```
#[derive(Clone, Copy, Debug, PartialEq)]
#[allow(missing_docs)]
pub enum Classification {
    CreatedNeverClassified,
    Unclassified,
    Ground,
    LowVegetation,
    MediumVegetation,
    HighVegetation,
    Building,
    LowPoint,
    ModelKeyPoint,
    Water,
    Rail,
    RoadSurface,
    WireGuard,
    WireConductor,
    TransmissionTower,
    WireStructureConnector,
    BridgeDeck,
    HighNoise,
    Reserved(u8),
    UserDefinable(u8),
}

impl Classification {
    /// Creates a new classification.
    ///
    /// Throws an error if the classification is 12 (overlap).
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Classification;
    /// assert_eq!(Classification::Ground, Classification::new(2).unwrap());
    /// assert!(Classification::new(12).is_err());
    /// ```
    pub fn new(n: u8) -> Result<Classification> {
        Ok(match n {
            0 => Classification::CreatedNeverClassified,
            1 => Classification::Unclassified,
            2 => Classification::Ground,
            3 => Classification::LowVegetation,
            4 => Classification::MediumVegetation,
            5 => Classification::HighVegetation,
            6 => Classification::Building,
            7 => Classification::LowPoint,
            8 => Classification::ModelKeyPoint,
            9 => Classification::Water,
            10 => Classification::Rail,
            11 => Classification::RoadSurface,
            12 => return Err(Error::OverlapClassification.into()),
            13 => Classification::WireGuard,
            14 => Classification::WireConductor,
            15 => Classification::TransmissionTower,
            16 => Classification::WireStructureConnector,
            17 => Classification::BridgeDeck,
            18 => Classification::HighNoise,
            19...63 => Classification::Reserved(n),
            64...255 => Classification::UserDefinable(n),
            _ => unreachable!(),
        })
    }
}

impl From<Classification> for u8 {
    fn from(classification: Classification) -> u8 {
        match classification {
            Classification::CreatedNeverClassified => 0,
            Classification::Unclassified => 1,
            Classification::Ground => 2,
            Classification::LowVegetation => 3,
            Classification::MediumVegetation => 4,
            Classification::HighVegetation => 5,
            Classification::Building => 6,
            Classification::LowPoint => 7,
            Classification::ModelKeyPoint => 8,
            Classification::Water => 9,
            Classification::Rail => 10,
            Classification::RoadSurface => 11,
            Classification::WireGuard => 13,
            Classification::WireConductor => 14,
            Classification::TransmissionTower => 15,
            Classification::WireStructureConnector => 16,
            Classification::BridgeDeck => 17,
            Classification::HighNoise => 18,
            Classification::Reserved(n) |
            Classification::UserDefinable(n) => n,
        }
    }
}

impl Default for Classification {
    fn default() -> Classification {
        Classification::CreatedNeverClassified
    }
}
<|endoftext|>


<commit_before>
use std::cmp::PartialEq;

//

pub fn append_vectors_once<'a, T: PartialEq + Copy, F: FnMut(T)>( dst : &'a mut Vec<T>, src : &'a Vec<Vec<T>>, on_evaluate : Option<F> ) -> &'a mut Vec<T>
{
  if on_evaluate.is_none()
  {
    for vec in src
    {
      for el in vec
      {
        if !dst.contains( el )
        {
          dst.push( *el );
        }
      }
    }
  }
  else
  {
    unimplemented!( "callbacks is not implemented" );
  }

  dst
}

<commit_msg>Implement trivial routine `left_index`<commit_after>
use std::cmp::PartialEq;

//

pub fn append_vectors_once<'a, T : PartialEq + Copy, F : FnMut(T)>( dst : &'a mut Vec<T>, src : &'a Vec<Vec<T>>, on_evaluate : Option<F> ) -> &'a mut Vec<T>
{
  if on_evaluate.is_none()
  {
    for vec in src
    {
      for el in vec
      {
        if !dst.contains( el )
        {
          dst.push( *el );
        }
      }
    }
  }
  else
  {
    unimplemented!( "callbacks is not implemented" );
  }

  dst
}

//

pub fn left_index<T : PartialEq + Copy, F : FnMut(T)>( src : &Vec<T>, el : T, on_evaluate1 : Option<F> ) -> Option<usize>
{
  if on_evaluate1.is_none()
  {
    return src.iter().position( | &x | x == el );
  }
  else
  {
    unimplemented!( "not implemented for callbacks" );
  }
}

<|endoftext|>