<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use fleetspeak_proto::common::{Message, Address};
use fleetspeak_proto::channel::{StartupData};
use lazy_static::lazy_static;
use prost;
use prost_types;
use std::io::{Read, Write, Result};
use std::marker::{Send, Sync};
use std::sync::Mutex;

pub struct Connection<R, W> {
    pub input: R,
    pub output: W,
    buf: Vec<u8>,
}

impl<R: Read, W: Write> Connection<R, W> {

    pub fn new(input: R, output: W) -> Self {
        Connection {
            input: input,
            output: output,
            buf: vec!(0; MAX_BUF_SIZE),
        }
    }

    pub fn heartbeat(&mut self) -> Result<()> {
        let msg = Message {
            message_type: "Heartbeat".to_string(),
            destination: Some(Address {
                service_name: "system".to_string(),
                ..Default::default()
            }),
            ..Default::default()
        };

        self.emit(msg)
    }

    pub fn handshake(&mut self, version: &str) -> Result<()> {
        let data = StartupData {
            pid: std::process::id() as i64,
            version: version.to_string(),
        };

        self.send("system", "StartupData", data)
    }

    pub fn send<M>(&mut self, service: &str, kind: &str, data: M) -> Result<()>
    where
        M: prost::Message,
    {
        let len = data.encoded_len();
        self.encode(data)?;

        let msg = Message {
            message_type: kind.to_string(),
            destination: Some(Address {
                service_name: service.to_string(),
                ..Default::default()
            }),
            data: Some(prost_types::Any {
                value: self.buf[..len].to_vec(),
                ..Default::default()
            }),
            ..Default::default()
        };

        self.emit(msg)
    }

    pub fn receive<M>(&mut self) -> Result<M>
    where
        M: prost::Message + Default,
    {
        let msg = self.collect()?;

        // It is not clear what is the best approach here. If there is no data,
        // should we error-out or return a default value? For the time being we
        // stick to the default approach, but if this proves to be not working
        // well in practice, it might be reconsidered.
        let data = match msg.data {
            Some(data) => data,
            None => return Ok(Default::default()),
        };

        prost::Message::decode(&data.value[..]).map_err(invalid_data_error)
    }

    fn emit(&mut self, msg: Message) -> Result<()> {
        let len = prost::Message::encoded_len(&msg);
        self.encode(msg)?;

        self.output.write_u32::<LittleEndian>(len as u32)?;
        self.output.write(&self.buf[..len])?;
        self.output.write_u32::<LittleEndian>(MAGIC)?;

        Ok(())
    }

    fn collect(&mut self) -> Result<Message> {
        let len = self.input.read_i32::<LittleEndian>()? as usize;
        self.input.read_exact(&mut self.buf[..len])?;

        prost::Message::decode(&self.buf[..len]).map_err(invalid_data_error)
    }

    fn encode<M>(&mut self, msg: M) -> Result<()>
    where
        M: prost::Message,
    {
        msg.encode(&mut self.buf).map_err(invalid_data_error)
    }
}

fn invalid_data_error<E>(err: E) -> std::io::Error
where
    E: Into<Box<dyn std::error::Error + Send + Sync>>,
{
    return std::io::Error::new(std::io::ErrorKind::InvalidData, err);
}

const MAGIC: u32 = 0xf1ee1001;
const MAX_BUF_SIZE: usize = 2 * 1024 * 1024;

fn open(var: &str) -> std::fs::File {
    let fd = match std::env::var(var) {
        Ok(fd) => fd,
        Err(err) => panic!("invalid variable `{}`: {}", var, err),
    };

    let fd = match fd.parse() {
        Ok(fd) => fd,
        Err(err) => panic!("failed to parse a file descriptor: {}", err),
    };

    // TODO: Add support for Windows.
    unsafe {
        std::os::unix::io::FromRawFd::from_raw_fd(fd)
    }
}

lazy_static! {
    static ref CONNECTION: Mutex<Connection<std::fs::File, std::fs::File>> = {
        let input = open("FLEETSPEAK_COMMS_CHANNEL_INFD");
        let output = open("FLEETSPEAK_COMMS_CHANNEL_OUTFD");

        let mut connection = Connection::new(input, output);
        // TODO: Add support for custom versions.
        if let Err(err) = connection.handshake("0.0.0") {
            panic!("handshake failure: {}", err);
        }

        Mutex::new(connection)
    };
}

pub fn heartbeat() -> Result<()> {
    connected(|conn| conn.heartbeat())
}

pub fn send<M>(service: &str, kind: &str, data: M) -> Result<()>
where
    M: prost::Message,
{
    connected(|conn| conn.send(service, kind, data))
}

pub fn receive<M>() -> Result<M>
where
    M: prost::Message + Default,
{
    connected(|conn| conn.receive())
}

fn connected<F, T>(f: F) -> Result<T>
where
    F: FnOnce(&mut Connection<std::fs::File, std::fs::File>) -> Result<T>
{
    let mut conn = CONNECTION.lock().expect("poisoned connection mutex");
    f(&mut conn)
}
<commit_msg>Add flushing when emitting messages.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use fleetspeak_proto::common::{Message, Address};
use fleetspeak_proto::channel::{StartupData};
use lazy_static::lazy_static;
use prost;
use prost_types;
use std::io::{Read, Write, Result};
use std::marker::{Send, Sync};
use std::sync::Mutex;

pub struct Connection<R, W> {
    pub input: R,
    pub output: W,
    buf: Vec<u8>,
}

impl<R: Read, W: Write> Connection<R, W> {

    pub fn new(input: R, output: W) -> Self {
        Connection {
            input: input,
            output: output,
            buf: vec!(0; MAX_BUF_SIZE),
        }
    }

    pub fn heartbeat(&mut self) -> Result<()> {
        let msg = Message {
            message_type: "Heartbeat".to_string(),
            destination: Some(Address {
                service_name: "system".to_string(),
                ..Default::default()
            }),
            ..Default::default()
        };

        self.emit(msg)
    }

    pub fn handshake(&mut self, version: &str) -> Result<()> {
        let data = StartupData {
            pid: std::process::id() as i64,
            version: version.to_string(),
        };

        self.send("system", "StartupData", data)
    }

    pub fn send<M>(&mut self, service: &str, kind: &str, data: M) -> Result<()>
    where
        M: prost::Message,
    {
        let len = data.encoded_len();
        self.encode(data)?;

        let msg = Message {
            message_type: kind.to_string(),
            destination: Some(Address {
                service_name: service.to_string(),
                ..Default::default()
            }),
            data: Some(prost_types::Any {
                value: self.buf[..len].to_vec(),
                ..Default::default()
            }),
            ..Default::default()
        };

        self.emit(msg)
    }

    pub fn receive<M>(&mut self) -> Result<M>
    where
        M: prost::Message + Default,
    {
        let msg = self.collect()?;

        // It is not clear what is the best approach here. If there is no data,
        // should we error-out or return a default value? For the time being we
        // stick to the default approach, but if this proves to be not working
        // well in practice, it might be reconsidered.
        let data = match msg.data {
            Some(data) => data,
            None => return Ok(Default::default()),
        };

        prost::Message::decode(&data.value[..]).map_err(invalid_data_error)
    }

    fn emit(&mut self, msg: Message) -> Result<()> {
        let len = prost::Message::encoded_len(&msg);
        self.encode(msg)?;

        self.output.write_u32::<LittleEndian>(len as u32)?;
        self.output.write(&self.buf[..len])?;
        self.output.write_u32::<LittleEndian>(MAGIC)?;
        self.output.flush()?;

        Ok(())
    }

    fn collect(&mut self) -> Result<Message> {
        let len = self.input.read_i32::<LittleEndian>()? as usize;
        self.input.read_exact(&mut self.buf[..len])?;

        prost::Message::decode(&self.buf[..len]).map_err(invalid_data_error)
    }

    fn encode<M>(&mut self, msg: M) -> Result<()>
    where
        M: prost::Message,
    {
        msg.encode(&mut self.buf).map_err(invalid_data_error)
    }
}

fn invalid_data_error<E>(err: E) -> std::io::Error
where
    E: Into<Box<dyn std::error::Error + Send + Sync>>,
{
    return std::io::Error::new(std::io::ErrorKind::InvalidData, err);
}

const MAGIC: u32 = 0xf1ee1001;
const MAX_BUF_SIZE: usize = 2 * 1024 * 1024;

fn open(var: &str) -> std::fs::File {
    let fd = match std::env::var(var) {
        Ok(fd) => fd,
        Err(err) => panic!("invalid variable `{}`: {}", var, err),
    };

    let fd = match fd.parse() {
        Ok(fd) => fd,
        Err(err) => panic!("failed to parse a file descriptor: {}", err),
    };

    // TODO: Add support for Windows.
    unsafe {
        std::os::unix::io::FromRawFd::from_raw_fd(fd)
    }
}

lazy_static! {
    static ref CONNECTION: Mutex<Connection<std::fs::File, std::fs::File>> = {
        let input = open("FLEETSPEAK_COMMS_CHANNEL_INFD");
        let output = open("FLEETSPEAK_COMMS_CHANNEL_OUTFD");

        let mut connection = Connection::new(input, output);
        // TODO: Add support for custom versions.
        if let Err(err) = connection.handshake("0.0.0") {
            panic!("handshake failure: {}", err);
        }

        Mutex::new(connection)
    };
}

pub fn heartbeat() -> Result<()> {
    connected(|conn| conn.heartbeat())
}

pub fn send<M>(service: &str, kind: &str, data: M) -> Result<()>
where
    M: prost::Message,
{
    connected(|conn| conn.send(service, kind, data))
}

pub fn receive<M>() -> Result<M>
where
    M: prost::Message + Default,
{
    connected(|conn| conn.receive())
}

fn connected<F, T>(f: F) -> Result<T>
where
    F: FnOnce(&mut Connection<std::fs::File, std::fs::File>) -> Result<T>
{
    let mut conn = CONNECTION.lock().expect("poisoned connection mutex");
    f(&mut conn)
}
<|endoftext|>


<commit_before>use std::io;
use std::io::IoResult;
use std::io::net::ip::SocketAddr;
use common::{Header, HTTPVersion, Method};
use Request;
use url::Path;
use sequential::{SequentialReader, SequentialReaderBuilder, SequentialWriterBuilder};
use util::ClosableTcpStream;

/// A ClientConnection is an object that will store a socket to a client
/// and return Request objects.
pub struct ClientConnection {
    // address of the client
    remote_addr: io::IoResult<SocketAddr>,

    // sequence of Readers to the stream, so that the data is not read in
    //  the wrong order
    source: SequentialReaderBuilder<ClosableTcpStream>,

    // sequence of Writers to the stream, to avoid writing response #2 before
    //  response #1
    sink: SequentialWriterBuilder<ClosableTcpStream>,

    // Reader to read the next header from
	next_header_source: SequentialReader<ClosableTcpStream>,

    // set to true if the client sent a "Connection: close" in the previous request
    connection_must_close: bool,
}

impl ClientConnection {
    /// Creates a new ClientConnection that takes ownership of the TcpStream.
    pub fn new(write_socket: ClosableTcpStream, mut read_socket: ClosableTcpStream)
        -> ClientConnection
    {
        let remote_addr = read_socket.peer_name();

        let mut source = SequentialReaderBuilder::new(read_socket);
        let first_header = source.next().unwrap();

        ClientConnection {
            source: source,
            sink: SequentialWriterBuilder::new(write_socket),
            remote_addr: remote_addr,
            next_header_source: first_header,
            connection_must_close: false,
        }
    }

    /// Reads the next line from self.next_header_source.
    ///
    /// Reads until `CRLF` is reached. The next read will start
    ///  at the first byte of the new line.
    fn read_next_line(&mut self) -> IoResult<String> {
        use std::io;
        use std::path::BytesContainer;

        let mut buf = Vec::new();
        let mut prev_byte_was_cr = false;

        loop {
            let byte = try!(self.next_header_source.read_byte());

            if byte == b'\n' && prev_byte_was_cr {
                return match buf.container_as_str() {
                    Some(s) => Ok(s.to_string()),
                    None => Err(io::standard_error(io::InvalidInput))
                }
            }

            if byte == b'\r' {
                prev_byte_was_cr = true;
            } else {
                prev_byte_was_cr = false;
            }

            buf.push(byte);
        }
    }

    /// Reads a request from the stream.
    /// Blocks until the header has been read.
    fn read(&mut self) -> io::IoResult<Request> {
        use util::EqualReader;

        let (method, path, version, headers) = {
            // reading the request line
            let (method, path, version) = {
                let line = try!(self.read_next_line());

                try!(parse_request_line(
                    line.as_slice().trim()
                ))
            };

            // getting all headers
            let headers = {
                let mut headers = Vec::new();
                loop {
                    let line = try!(self.read_next_line());

                    if line.as_slice().trim().len() == 0 { break };
                    headers.push(
                        match from_str(line.as_slice().trim()) {
                            Some(h) => h,
                            None => return Err(gen_invalid_input(
                                "Could not parse header"))
                        }
                    );
                }
                headers
            };

            (method, path, version, headers)
        };

        // finding length of body
        // TODO: handle transfer-encoding
        let body_length = headers.iter()
            .find(|h: &&Header| h.field.equiv(&"Content-Length"))
            .and_then(|h| from_str::<uint>(h.value.as_slice()))
            .unwrap_or(0u);

        // building the next reader
        let request_body_reader =
            if body_length == 0 {
                use std::io::util::NullReader;
                box NullReader as Box<Reader + Send>

            } else if body_length <= 1024 {
                use std::io::MemReader;
                let data = try!(self.next_header_source.read_exact(body_length));
                box MemReader::new(data) as Box<Reader + Send>

            } else {
                let data_reader = self.source.next().unwrap();
                let (data_reader, _) = EqualReader::new(data_reader, body_length);   // TODO:
                box data_reader as Box<Reader + Send>
            };

        // follow-up for next potential request
        self.next_header_source = self.source.next().unwrap();

        // building the writer
        let writer = self.sink.next().unwrap();

        // building the request
        Ok(Request {
            data_reader: request_body_reader,
            response_writer: box writer,
            remote_addr: self.remote_addr.clone().unwrap(),     // TODO: could fail
            method: method,
            path: path,
            http_version: version,
            headers: headers,
            body_length: body_length,
        })
    }
}

impl Iterator<Request> for ClientConnection {
    /// Blocks until the next Request is available.
    /// Returns None when no new Requests will come from the client.
    fn next(&mut self) -> Option<Request> {
        // the client sent a "connection: close" header in this previous request
        //  or is using HTTP 1.0, meaning that no new request will come
        if self.connection_must_close {
            return None
        }

        // TODO: send back message to client in case of parsing error
        loop {
            let rq = match self.read() {
                Err(_) => return None,
                Ok(rq) => rq
            };

            // updating the status of the connection
            {
                let connection_header = rq.headers.iter()
                    .find(|h| h.field.equiv(&"Connection")).map(|h| h.value.as_slice());

                if connection_header == Some("close") {
                    self.connection_must_close = true;
                } else if rq.http_version == HTTPVersion(1, 0) &&
                        connection_header != Some("keep-alive")
                {
                    self.connection_must_close = true;
                }
            }

            // returning the request
            return Some(rq);
        }
    }
}

/// Generates an IoError with invalid input.
/// This function is here because it is incredibly annoying to create this error.
fn gen_invalid_input(desc: &'static str) -> io::IoError {
    io::IoError {
        kind: io::InvalidInput,
        desc: desc,
        detail: None
    }
}

/// Parses a "HTTP/1.1" string.
fn parse_http_version(version: &str) -> io::IoResult<HTTPVersion> {
    let elems = version.splitn('/', 2).map(|e| e.to_string()).collect::<Vec<String>>();
    if elems.len() != 2 {
        return Err(gen_invalid_input("Wrong HTTP version format"))
    }

    let elems = elems.get(1).as_slice().splitn('.', 2)
        .map(|e| e.to_string()).collect::<Vec<String>>();
    if elems.len() != 2 {
        return Err(gen_invalid_input("Wrong HTTP version format"))
    }

    match (from_str(elems.get(0).as_slice()), from_str(elems.get(1).as_slice())) {
        (Some(major), Some(minor)) =>
            Ok(HTTPVersion(major, minor)),
        _ => Err(gen_invalid_input("Wrong HTTP version format"))
    }
}

/// Parses the request line of the request.
/// eg. GET / HTTP/1.1
fn parse_request_line(line: &str) -> io::IoResult<(Method, Path, HTTPVersion)> {
    let mut words = line.words();

    let method = words.next();
    let path = words.next();
    let version = words.next();

    let (method, path, version) = match (method, path, version) {
        (Some(m), Some(p), Some(v)) => (m, p, v),
        _ => return Err(gen_invalid_input("Missing element in request line"))
    };

    let method = match from_str(method) {
        Some(method) => method,
        None => return Err(gen_invalid_input("Could not parse method"))
    };

    let path = match Path::parse(path) {
        Ok(p) => p,
        Err(_) => return Err(gen_invalid_input("Wrong requested URL"))
    };

    let version = try!(parse_http_version(version));

    Ok((method, path, version))
}

#[cfg(test)]
mod test {
    #[test]
    fn test_parse_request_line() {
        let (method, path, ver) =
            super::parse_request_line("GET /hello HTTP/1.1").unwrap();

        assert!(method.equiv(&"get"));
        assert!(path == from_str("/hello").unwrap());
        assert!(ver == ::common::HTTPVersion(1, 1));

        assert!(super::parse_request_line("GET /hello").is_err());
        assert!(super::parse_request_line("qsd qsd qsd").is_err());
    }
}
<commit_msg>Now using BufferedReader/BufferedWriter<commit_after>use std::io;
use std::io::{BufferedReader, BufferedWriter, IoResult};
use std::io::net::ip::SocketAddr;
use common::{Header, HTTPVersion, Method};
use Request;
use url::Path;
use sequential::{SequentialReader, SequentialReaderBuilder, SequentialWriterBuilder};
use util::ClosableTcpStream;

/// A ClientConnection is an object that will store a socket to a client
/// and return Request objects.
pub struct ClientConnection {
    // address of the client
    remote_addr: io::IoResult<SocketAddr>,

    // sequence of Readers to the stream, so that the data is not read in
    //  the wrong order
    source: SequentialReaderBuilder<BufferedReader<ClosableTcpStream>>,

    // sequence of Writers to the stream, to avoid writing response #2 before
    //  response #1
    sink: SequentialWriterBuilder<BufferedWriter<ClosableTcpStream>>,

    // Reader to read the next header from
	next_header_source: SequentialReader<BufferedReader<ClosableTcpStream>>,

    // set to true if the client sent a "Connection: close" in the previous request
    connection_must_close: bool,
}

impl ClientConnection {
    /// Creates a new ClientConnection that takes ownership of the TcpStream.
    pub fn new(write_socket: ClosableTcpStream, mut read_socket: ClosableTcpStream)
        -> ClientConnection
    {
        let remote_addr = read_socket.peer_name();

        let mut source = SequentialReaderBuilder::new(BufferedReader::new(read_socket));
        let first_header = source.next().unwrap();

        ClientConnection {
            source: source,
            sink: SequentialWriterBuilder::new(BufferedWriter::new(write_socket)),
            remote_addr: remote_addr,
            next_header_source: first_header,
            connection_must_close: false,
        }
    }

    /// Reads the next line from self.next_header_source.
    ///
    /// Reads until `CRLF` is reached. The next read will start
    ///  at the first byte of the new line.
    fn read_next_line(&mut self) -> IoResult<String> {
        use std::io;
        use std::path::BytesContainer;

        let mut buf = Vec::new();
        let mut prev_byte_was_cr = false;

        loop {
            let byte = try!(self.next_header_source.read_byte());

            if byte == b'\n' && prev_byte_was_cr {
                return match buf.container_as_str() {
                    Some(s) => Ok(s.to_string()),
                    None => Err(io::standard_error(io::InvalidInput))
                }
            }

            if byte == b'\r' {
                prev_byte_was_cr = true;
            } else {
                prev_byte_was_cr = false;
            }

            buf.push(byte);
        }
    }

    /// Reads a request from the stream.
    /// Blocks until the header has been read.
    fn read(&mut self) -> io::IoResult<Request> {
        use util::EqualReader;

        let (method, path, version, headers) = {
            // reading the request line
            let (method, path, version) = {
                let line = try!(self.read_next_line());

                try!(parse_request_line(
                    line.as_slice().trim()
                ))
            };

            // getting all headers
            let headers = {
                let mut headers = Vec::new();
                loop {
                    let line = try!(self.read_next_line());

                    if line.as_slice().trim().len() == 0 { break };
                    headers.push(
                        match from_str(line.as_slice().trim()) {
                            Some(h) => h,
                            None => return Err(gen_invalid_input(
                                "Could not parse header"))
                        }
                    );
                }
                headers
            };

            (method, path, version, headers)
        };

        // finding length of body
        // TODO: handle transfer-encoding
        let body_length = headers.iter()
            .find(|h: &&Header| h.field.equiv(&"Content-Length"))
            .and_then(|h| from_str::<uint>(h.value.as_slice()))
            .unwrap_or(0u);

        // building the next reader
        let request_body_reader =
            if body_length == 0 {
                use std::io::util::NullReader;
                box NullReader as Box<Reader + Send>

            } else if body_length <= 1024 {
                use std::io::MemReader;
                let data = try!(self.next_header_source.read_exact(body_length));
                box MemReader::new(data) as Box<Reader + Send>

            } else {
                let data_reader = self.source.next().unwrap();
                let (data_reader, _) = EqualReader::new(data_reader, body_length);   // TODO:
                box data_reader as Box<Reader + Send>
            };

        // follow-up for next potential request
        self.next_header_source = self.source.next().unwrap();

        // building the writer
        let writer = self.sink.next().unwrap();

        // building the request
        Ok(Request {
            data_reader: request_body_reader,
            response_writer: box writer,
            remote_addr: self.remote_addr.clone().unwrap(),     // TODO: could fail
            method: method,
            path: path,
            http_version: version,
            headers: headers,
            body_length: body_length,
        })
    }
}

impl Iterator<Request> for ClientConnection {
    /// Blocks until the next Request is available.
    /// Returns None when no new Requests will come from the client.
    fn next(&mut self) -> Option<Request> {
        // the client sent a "connection: close" header in this previous request
        //  or is using HTTP 1.0, meaning that no new request will come
        if self.connection_must_close {
            return None
        }

        // TODO: send back message to client in case of parsing error
        loop {
            let rq = match self.read() {
                Err(_) => return None,
                Ok(rq) => rq
            };

            // updating the status of the connection
            {
                let connection_header = rq.headers.iter()
                    .find(|h| h.field.equiv(&"Connection")).map(|h| h.value.as_slice());

                if connection_header == Some("close") {
                    self.connection_must_close = true;
                } else if rq.http_version == HTTPVersion(1, 0) &&
                        connection_header != Some("keep-alive")
                {
                    self.connection_must_close = true;
                }
            }

            // returning the request
            return Some(rq);
        }
    }
}

/// Generates an IoError with invalid input.
/// This function is here because it is incredibly annoying to create this error.
fn gen_invalid_input(desc: &'static str) -> io::IoError {
    io::IoError {
        kind: io::InvalidInput,
        desc: desc,
        detail: None
    }
}

/// Parses a "HTTP/1.1" string.
fn parse_http_version(version: &str) -> io::IoResult<HTTPVersion> {
    let elems = version.splitn('/', 2).map(|e| e.to_string()).collect::<Vec<String>>();
    if elems.len() != 2 {
        return Err(gen_invalid_input("Wrong HTTP version format"))
    }

    let elems = elems.get(1).as_slice().splitn('.', 2)
        .map(|e| e.to_string()).collect::<Vec<String>>();
    if elems.len() != 2 {
        return Err(gen_invalid_input("Wrong HTTP version format"))
    }

    match (from_str(elems.get(0).as_slice()), from_str(elems.get(1).as_slice())) {
        (Some(major), Some(minor)) =>
            Ok(HTTPVersion(major, minor)),
        _ => Err(gen_invalid_input("Wrong HTTP version format"))
    }
}

/// Parses the request line of the request.
/// eg. GET / HTTP/1.1
fn parse_request_line(line: &str) -> io::IoResult<(Method, Path, HTTPVersion)> {
    let mut words = line.words();

    let method = words.next();
    let path = words.next();
    let version = words.next();

    let (method, path, version) = match (method, path, version) {
        (Some(m), Some(p), Some(v)) => (m, p, v),
        _ => return Err(gen_invalid_input("Missing element in request line"))
    };

    let method = match from_str(method) {
        Some(method) => method,
        None => return Err(gen_invalid_input("Could not parse method"))
    };

    let path = match Path::parse(path) {
        Ok(p) => p,
        Err(_) => return Err(gen_invalid_input("Wrong requested URL"))
    };

    let version = try!(parse_http_version(version));

    Ok((method, path, version))
}

#[cfg(test)]
mod test {
    #[test]
    fn test_parse_request_line() {
        let (method, path, ver) =
            super::parse_request_line("GET /hello HTTP/1.1").unwrap();

        assert!(method.equiv(&"get"));
        assert!(path == from_str("/hello").unwrap());
        assert!(ver == ::common::HTTPVersion(1, 1));

        assert!(super::parse_request_line("GET /hello").is_err());
        assert!(super::parse_request_line("qsd qsd qsd").is_err());
    }
}
<|endoftext|>


<commit_before>//! # Basic usage
//!
//! Visiting the accessors of a glTF asset.
//!
//! ```
//! # fn run() -> Result<(), Box<std::error::Error>> {
//! # let gltf = gltf::Gltf::open("examples/Box.gltf")?;
//! for accessor in gltf.accessors() {
//!     println!("Accessor #{}", accessor.index());
//!     println!("offset: {}", accessor.offset());
//!     println!("count: {}", accessor.count());
//!     println!("data_type: {:?}", accessor.data_type());
//!     println!("dimensions: {:?}", accessor.dimensions());
//! }
//! # Ok(())
//! # }
//! # fn main() {
//! #    let _ = run().expect("runtime error");
//! # }
//! ```
//!
//! # Utility functions
//!
//! Reading the values from the `vec3` accessors of a glTF asset.
//!
//! ## Note
//!
//! The [`Iter`] utility is a low-level iterator intended for use in special
//! cases. The average user is expected to use reader abstractions such as
//! [`mesh::Reader`].
//!
//! [`Iter`]: struct.Iter.html
//! [`mesh::Reader`]: ../mesh/struct.Reader.html
//!
//! ```
//! # fn run() -> Result<(), Box<std::error::Error>> {
//! # use gltf::accessor::{DataType, Dimensions, Iter};
//! let (gltf, buffers, _) = gltf::import("examples/Box.gltf")?;
//! for accessor in gltf.accessors() {
//!     match (accessor.data_type(), accessor.dimensions()) {
//!         (DataType::F32, Dimensions::Vec3) => {
//!             let buffer_index = accessor.view().buffer().index();
//!             let buffer_data = buffers[buffer_index].0.as_slice();
//!             let iter = Iter::<[f32; 3]>::new(accessor, buffer_data);
//!             for item in iter {
//!                 println!("{:?}", item);
//!             }
//!         }
//!         _ => {},
//!     }
//! }
//! # Ok(())
//! # }
//! # fn main() {
//! #    let _ = run().expect("runtime error");
//! # }
//! ```

use {buffer, json};

use Document;

pub use json::accessor::ComponentType as DataType;
pub use json::accessor::Type as Dimensions;

/// Utility functions.
#[cfg(feature = "utils")]
pub mod util;

/// Contains data structures for sparse storage.
pub mod sparse;

#[cfg(feature = "utils")]
#[doc(inline)]
pub use self::util::{Item, Iter};

/// A typed view into a buffer view.
#[derive(Clone, Debug)]
pub struct Accessor<'a> {
    /// The parent `Document` struct.
    document: &'a Document,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::accessor::Accessor,

    /// The buffer view this accessor reads from.
    view: buffer::View<'a>,
}

impl<'a> Accessor<'a> {
    /// Constructs an `Accessor`.
    pub(crate) fn new(
        document: &'a Document,
        index: usize,
        json: &'a json::accessor::Accessor,
    ) -> Self {
        let view = document.views().nth(json.buffer_view.value()).unwrap();
        Self {
            document,
            index,
            json,
            view,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Returns the size of each component that this accessor describes.
    pub fn size(&self) -> usize {
        self.data_type().size() * self.dimensions().multiplicity()
    }

    /// Returns the buffer view this accessor reads from.
    pub fn view(&self) -> buffer::View<'a> {
        self.document.views().nth(self.json.buffer_view.value()).unwrap()
    }

    /// Returns the offset relative to the start of the parent buffer view in bytes.
    pub fn offset(&self) -> usize {
        self.json.byte_offset as usize
    }

    /// Returns the number of components within the buffer view - not to be confused
    /// with the number of bytes in the buffer view.
    pub fn count(&self) -> usize {
        self.json.count as usize
    }

    /// Returns the data type of components in the attribute.
    pub fn data_type(&self) -> DataType {
        self.json.component_type.unwrap().0
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }

    /// Specifies if the attribute is a scalar, vector, or matrix.
    pub fn dimensions(&self) -> Dimensions {
        self.json.type_.unwrap()
    }

    /// Returns the minimum value of each component in this attribute.
    pub fn min(&self) -> Option<json::Value> {
        self.json.min.clone()
    }

    /// Returns the maximum value of each component in this attribute.
    pub fn max(&self) -> Option<json::Value> {
        self.json.max.clone()
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// Specifies whether integer data values should be normalized.
    pub fn normalized(&self) -> bool {
        self.json.normalized
    }

    /// Returns sparse storage of attributes that deviate from their initialization
    /// value.
    pub fn sparse(&self) -> Option<sparse::Sparse> {
        self.json.sparse.as_ref().map(|json| {
            sparse::Sparse::new(self.document, json)
        })
    }
}
<commit_msg>Fix accessor performance<commit_after>//! # Basic usage
//!
//! Visiting the accessors of a glTF asset.
//!
//! ```
//! # fn run() -> Result<(), Box<std::error::Error>> {
//! # let gltf = gltf::Gltf::open("examples/Box.gltf")?;
//! for accessor in gltf.accessors() {
//!     println!("Accessor #{}", accessor.index());
//!     println!("offset: {}", accessor.offset());
//!     println!("count: {}", accessor.count());
//!     println!("data_type: {:?}", accessor.data_type());
//!     println!("dimensions: {:?}", accessor.dimensions());
//! }
//! # Ok(())
//! # }
//! # fn main() {
//! #    let _ = run().expect("runtime error");
//! # }
//! ```
//!
//! # Utility functions
//!
//! Reading the values from the `vec3` accessors of a glTF asset.
//!
//! ## Note
//!
//! The [`Iter`] utility is a low-level iterator intended for use in special
//! cases. The average user is expected to use reader abstractions such as
//! [`mesh::Reader`].
//!
//! [`Iter`]: struct.Iter.html
//! [`mesh::Reader`]: ../mesh/struct.Reader.html
//!
//! ```
//! # fn run() -> Result<(), Box<std::error::Error>> {
//! # use gltf::accessor::{DataType, Dimensions, Iter};
//! let (gltf, buffers, _) = gltf::import("examples/Box.gltf")?;
//! for accessor in gltf.accessors() {
//!     match (accessor.data_type(), accessor.dimensions()) {
//!         (DataType::F32, Dimensions::Vec3) => {
//!             let buffer_index = accessor.view().buffer().index();
//!             let buffer_data = buffers[buffer_index].0.as_slice();
//!             let iter = Iter::<[f32; 3]>::new(accessor, buffer_data);
//!             for item in iter {
//!                 println!("{:?}", item);
//!             }
//!         }
//!         _ => {},
//!     }
//! }
//! # Ok(())
//! # }
//! # fn main() {
//! #    let _ = run().expect("runtime error");
//! # }
//! ```

use {buffer, json};

use Document;

pub use json::accessor::ComponentType as DataType;
pub use json::accessor::Type as Dimensions;

/// Utility functions.
#[cfg(feature = "utils")]
pub mod util;

/// Contains data structures for sparse storage.
pub mod sparse;

#[cfg(feature = "utils")]
#[doc(inline)]
pub use self::util::{Item, Iter};

/// A typed view into a buffer view.
#[derive(Clone, Debug)]
pub struct Accessor<'a> {
    /// The parent `Document` struct.
    document: &'a Document,

    /// The corresponding JSON index.
    index: usize,

    /// The corresponding JSON struct.
    json: &'a json::accessor::Accessor,
}

impl<'a> Accessor<'a> {
    /// Constructs an `Accessor`.
    pub(crate) fn new(
        document: &'a Document,
        index: usize,
        json: &'a json::accessor::Accessor,
    ) -> Self {
        Self {
            document,
            index,
            json,
        }
    }

    /// Returns the internal JSON index.
    pub fn index(&self) -> usize {
        self.index
    }

    /// Returns the size of each component that this accessor describes.
    pub fn size(&self) -> usize {
        self.data_type().size() * self.dimensions().multiplicity()
    }

    /// Returns the buffer view this accessor reads from.
    pub fn view(&self) -> buffer::View<'a> {
        self.document.views().nth(self.json.buffer_view.value()).unwrap()
    }

    /// Returns the offset relative to the start of the parent buffer view in bytes.
    pub fn offset(&self) -> usize {
        self.json.byte_offset as usize
    }

    /// Returns the number of components within the buffer view - not to be confused
    /// with the number of bytes in the buffer view.
    pub fn count(&self) -> usize {
        self.json.count as usize
    }

    /// Returns the data type of components in the attribute.
    pub fn data_type(&self) -> DataType {
        self.json.component_type.unwrap().0
    }

    /// Optional application specific data.
    pub fn extras(&self) -> &json::Extras {
        &self.json.extras
    }

    /// Specifies if the attribute is a scalar, vector, or matrix.
    pub fn dimensions(&self) -> Dimensions {
        self.json.type_.unwrap()
    }

    /// Returns the minimum value of each component in this attribute.
    pub fn min(&self) -> Option<json::Value> {
        self.json.min.clone()
    }

    /// Returns the maximum value of each component in this attribute.
    pub fn max(&self) -> Option<json::Value> {
        self.json.max.clone()
    }

    /// Optional user-defined name for this object.
    #[cfg(feature = "names")]
    pub fn name(&self) -> Option<&str> {
        self.json.name.as_ref().map(String::as_str)
    }

    /// Specifies whether integer data values should be normalized.
    pub fn normalized(&self) -> bool {
        self.json.normalized
    }

    /// Returns sparse storage of attributes that deviate from their initialization
    /// value.
    pub fn sparse(&self) -> Option<sparse::Sparse> {
        self.json.sparse.as_ref().map(|json| {
            sparse::Sparse::new(self.document, json)
        })
    }
}
<|endoftext|>


<commit_before>use std::io::BufReader;
use self::Token::{
	TokPassageName, TokTagStart, TokTagEnd, TokTag,
	TokMakroStart, TokMakroEnd, TokVariable,
	TokSet, TokAssign, TokInt, TokFloat, TokNumOp, TokCompOp,
	TokLogOp, TokText, TokFormatBold, TokFormatItalic,
	TokFormatUnder,	TokFormatStrike, TokFormatSub, TokFormatSup,
	TokFormatMonoStart,	TokFormatMonoEnd, TokString, TokBracketOpen,
	TokBracketClose, TokIf, TokElse, TokEndIf, TokPassageLink
};

pub fn lex(input :String) -> Vec<Token> {
   	let inp = BufReader::new(input.as_bytes());
	let lexer = TweeLexer::new(inp);
	lexer.collect()
}

#[derive(PartialEq,Debug)]
pub enum Token {
	TokPassageName (String),
	TokTagStart,
	TokTagEnd,
	TokPassageLink (String, String),
	TokTag (String),
	TokText (String),
	TokFormatBold,
	TokFormatItalic,
	TokFormatUnder,
	TokFormatStrike,
	TokFormatSub,
	TokFormatSup,
	TokFormatMonoStart,
	TokFormatMonoEnd,
	TokMakroStart,
	TokMakroEnd,
	TokBracketOpen,
	TokBracketClose,
	TokVariable (String),
	TokInt (i32),
	TokFloat (f32),
	TokString (String),
	TokSet,
	TokAssign,
	TokNumOp (String),
	TokCompOp (String),
	TokLogOp (String),
	TokIf,
	TokElse,
	TokEndIf
}

rustlex! TweeLexer {
	let DIGIT = ['0'-'9'];
	let LETTER_S = ['a'-'z'];
	let LETTER_L = ['A'-'Z'];
	let LETTER = (LETTER_S|LETTER_L);
	let SPECIAL = ["'._$"];
	let SPACE = ' ';
	let UNDERSCORE = '_';
	let NEWLINE = '\n';

	let CHAR = LETTER_S | LETTER_L | DIGIT | SPECIAL;
	let WORD = CHAR CHAR*;

	// TODO what is allowed?
	let TEXT = (LETTER | DIGIT | SPACE | NEWLINE)+;
	let TEXTLINES = (LETTER | DIGIT | SPACE | NEWLINE)+;

	let PASSAGE_CHAR = SPACE | LETTER_S | LETTER_L | DIGIT | SPECIAL;
	let PASSAGE_START = "::";
	let PASSAGE_NAME = PASSAGE_CHAR PASSAGE_CHAR*;
	let TAG_START = '[';
	let TAG_END = ']';

	let LINK_SIMPLE = "[[" PASSAGE_NAME "]]";
	let LINK_LABELED = "[[" TEXT "|" PASSAGE_NAME "]]";

	let FORMAT_ITALIC = "//";
	let FORMAT_BOLD = '"';
	let FORMAT_UNDER = "__";
	let FORMAT_STRIKE = "==";
	let FORMAT_SUB = "~~";
	let FORMAT_SUP = "^^";
	let FORMAT_MONO_START = "{{{";
	let FORMAT_MONO_END = "}}}";

	let MAKRO_START = "<<";
	let MAKRO_END = ">>";

	let BR_OPEN = '(';
	let BR_CLOSE = ')';

	let VAR_CHAR = LETTER | DIGIT | UNDERSCORE;
	let VAR_NAME = '$' (LETTER | UNDERSCORE) VAR_CHAR*;

	let NUMBER = DIGIT DIGIT*;
	let INT = '-'? NUMBER;
	// TODO exact definition of float in twee
	let FLOAT = (INT "." NUMBER?) | ("." NUMBER);

	let STRING = ('"' [^'"']* '"') | ("'" [^"'"]* "'");

	let SET = "set";
	let ASSIGN = "=" | "to";
	let IF = "if";
	let ELSE = "else";
	let END_IF = "endif";

	let NUM_OP = ["+-*/%"];
	let COMP_OP = "is" | "==" | "eq" | "neq" | ">" | "gt" | ">=" | "gte" | "<" | "lt" | "<=" | "lte";
	let LOG_OP = "and" | "or" | "not";

	INITIAL {
		PASSAGE_START => |lexer:&mut TweeLexer<R>| -> Option<Token>{
			lexer.PASSAGE();
			None
		}

		MAKRO_START => |lexer:&mut TweeLexer<R>| {
			lexer.MAKRO();
			Some(TokMakroStart)
		}

		LINK_SIMPLE =>  |lexer:&mut TweeLexer<R>| {
			let s =  lexer.yystr();
			let trimmed = &s[2 .. s.len()-2];
			let name = &trimmed.to_string();
			Some(TokPassageLink(name.clone(), name.clone()))
		}

		LINK_LABELED =>  |lexer:&mut TweeLexer<R>| {
			let s =  lexer.yystr();
			let trimmed = &s[2 .. s.len()-2];
			let matches = &trimmed.split("|").collect::<Vec<&str>>();
			assert_eq!(matches.len(), 2);
			let text = matches[0].to_string();
			let name = matches[1].to_string();
			Some(TokPassageLink(text, name))
		}

		FORMAT_ITALIC => |_:&mut TweeLexer<R>| Some(TokFormatItalic)
		FORMAT_BOLD => |_:&mut TweeLexer<R>| Some(TokFormatBold)
		FORMAT_UNDER => |_:&mut TweeLexer<R>| Some(TokFormatUnder)
		FORMAT_STRIKE => |_:&mut TweeLexer<R>| Some(TokFormatStrike)
		FORMAT_SUB => |_:&mut TweeLexer<R>| Some(TokFormatSub)
		FORMAT_SUP => |_:&mut TweeLexer<R>| Some(TokFormatSup)
		FORMAT_MONO_START => |_:&mut TweeLexer<R>| Some(TokFormatMonoStart)
		FORMAT_MONO_END => |_:&mut TweeLexer<R>| Some(TokFormatMonoEnd)

		TEXTLINES => |lexer:&mut TweeLexer<R>| Some(TokText(lexer.yystr()))
	}

	PASSAGE {
		// TODO trim()
		PASSAGE_NAME => |lexer:&mut TweeLexer<R>| Some(TokPassageName(lexer.yystr()))
		TAG_START => |lexer:&mut TweeLexer<R>| {
			lexer.TAGS();
			Some(TokTagStart)
		}
		NEWLINE => |lexer:&mut TweeLexer<R>| -> Option<Token>{
			lexer.INITIAL();
			None
		}
	}

	TAGS {
		WORD => |lexer:&mut TweeLexer<R>| Some(TokTag(lexer.yystr()))
		TAG_END => |lexer:&mut TweeLexer<R>| {
			lexer.PASSAGE();
			Some(TokTagEnd)
		}
	}

	MAKRO {
		MAKRO_END => |lexer:&mut TweeLexer<R>| {
			lexer.INITIAL();
			Some(TokMakroEnd)
		}
		VAR_NAME =>  |lexer:&mut TweeLexer<R>| Some(TokVariable(lexer.yystr()))
		FLOAT =>  |lexer:&mut TweeLexer<R>| Some(TokFloat(lexer.yystr()[..].parse().unwrap()))
		INT =>  |lexer:&mut TweeLexer<R>| Some(TokInt(lexer.yystr()[..].parse().unwrap()))
		STRING =>  |lexer:&mut TweeLexer<R>| Some(TokString(lexer.yystr()))
		SET =>  |_:&mut TweeLexer<R>| Some(TokSet)
		ASSIGN =>  |_:&mut TweeLexer<R>| Some(TokAssign)
		IF =>  |_:&mut TweeLexer<R>| Some(TokIf)
		ELSE =>  |_:&mut TweeLexer<R>| Some(TokElse)
		END_IF =>  |_:&mut TweeLexer<R>| Some(TokEndIf)
		NUM_OP =>  |lexer:&mut TweeLexer<R>| Some(TokNumOp(lexer.yystr()))
		COMP_OP =>  |lexer:&mut TweeLexer<R>| Some(TokCompOp(lexer.yystr()))
		LOG_OP =>  |lexer:&mut TweeLexer<R>| Some(TokLogOp(lexer.yystr()))
		BR_OPEN =>  |_:&mut TweeLexer<R>| Some(TokBracketOpen)
		BR_CLOSE =>  |_:&mut TweeLexer<R>| Some(TokBracketClose)
	}

}

#[test]
fn it_works() {

}
<commit_msg>Add new formats (lists, headings, indents) and preprocessing for deletion of comments<commit_after>use std::io::BufReader;
use self::Token::{
	TokPassageName, TokTagStart, TokTagEnd, TokTag,
	TokMakroStart, TokMakroEnd, TokVariable,
	TokSet, TokAssign, TokInt, TokFloat, TokNumOp, TokCompOp,
	TokLogOp, TokText, TokFormatBold, TokFormatItalic,
	TokFormatUnder,	TokFormatStrike, TokFormatSub, TokFormatSup,
	TokFormatMonoStart,	TokFormatMonoEnd, TokString, TokBracketOpen,
	TokBracketClose, TokIf, TokElse, TokEndIf, TokPassageLink,
	TokFormatBulList, TokFormatNumbList, TokFormatIndent,
	TokFormatIndentDouble, TokFormatIndentBlock, TokFormatHeading
};

pub fn lex(input :String) -> Vec<Token> {
	let processed = preprocess(input);
	println!("Processed Text is:\n{:?}", processed);
   	let inp = BufReader::new(processed.as_bytes());
	let lexer = TweeLexer::new(inp);
	lexer.collect()
}

fn preprocess(input :String) -> String {
	let mut comment = false;
	let mut suspect_start = false;
	let mut suspect_end = false;
	let mut processed = String::new();

	for c in input.chars() {
		if !comment && !suspect_start && c == '/' {
			suspect_start = true;
			continue;
		}

		if suspect_start {
			if c == '%' {
				comment = true;
				suspect_start = false;
			} else {
				suspect_start = false;
				processed.push('/');
			}

			continue;
		}

		if c == '%' && comment {
			suspect_end = true;
			continue;
		}

		if suspect_end {
			if c == '/' {
				comment = false;
				suspect_end = false;
			} else {
				suspect_end = false;
			}
			continue;
		}

		if !comment {
			processed.push(c);
		}
	}

	processed
}

#[derive(PartialEq,Debug)]
pub enum Token {
	TokPassageName (String),
	TokTagStart,
	TokTagEnd,
	TokPassageLink (String, String),
	TokTag (String),
	TokText (String),
	TokFormatBold,
	TokFormatItalic,
	TokFormatUnder,
	TokFormatStrike,
	TokFormatSub,
	TokFormatSup,
	TokFormatMonoStart,
	TokFormatMonoEnd,
	TokFormatBulList,
	TokFormatNumbList,
	TokFormatIndent,
	TokFormatIndentDouble,
	TokFormatIndentBlock,
	TokFormatHeading (usize),
	TokMakroStart,
	TokMakroEnd,
	TokBracketOpen,
	TokBracketClose,
	TokVariable (String),
	TokInt (i32),
	TokFloat (f32),
	TokString (String),
	TokSet,
	TokAssign,
	TokNumOp (String),
	TokCompOp (String),
	TokLogOp (String),
	TokIf,
	TokElse,
	TokEndIf
}

rustlex! TweeLexer {
	let DIGIT = ['0'-'9'];
	let LETTER_S = ['a'-'z'];
	let LETTER_L = ['A'-'Z'];
	let LETTER = (LETTER_S|LETTER_L);
	let SPECIAL = ["'.$"] | ('_' [^'_']) | ["äöüÄÖÜß"];
	let SPACE = ' ';
	let UNDERSCORE = '_';
	let NEWLINE = '\n';

	let CHAR = LETTER_S | LETTER_L | DIGIT | SPECIAL;
	let WORD = CHAR CHAR*;

	// TODO what is allowed?
	let TEXT = (CHAR | SPACE)+;
	let TEXTLINES = (CHAR | SPACE | NEWLINE)+;

	let PASSAGE_CHAR = SPACE | LETTER_S | LETTER_L | DIGIT | SPECIAL;
	let PASSAGE_START = "::";
	let PASSAGE_NAME = PASSAGE_CHAR PASSAGE_CHAR*;
	let TAG_START = '[';
	let TAG_END = ']';

	let LINK_SIMPLE = "[[" PASSAGE_NAME "]]";
	let LINK_LABELED = "[[" TEXT "|" PASSAGE_NAME "]]";

	let FORMAT_ITALIC = "//";
	let FORMAT_BOLD = '"';
	let FORMAT_UNDER = "__";
	let FORMAT_STRIKE = "==";
	let FORMAT_SUB = "~~";
	let FORMAT_SUP = "^^";
	let FORMAT_MONO_START = "{{{";
	let FORMAT_MONO_END = "}}}";

	let FORMAT_BUL_LIST = "*";
	let FORMAT_NUMB_LIST = "#";
	let FORMAT_INDENT = ">";
	let FORMAT_DOUBLE_INDENT = ">>";
	let FORMAT_INDENT_BLOCK = "<<<";

	let FORMAT_HEADING = "!" | "!!" | "!!!" | "!!!!" | "!!!!!";

	let MAKRO_START = "<<";
	let MAKRO_END = ">>";

	let BR_OPEN = '(';
	let BR_CLOSE = ')';

	let VAR_CHAR = LETTER | DIGIT | UNDERSCORE;
	let VAR_NAME = '$' (LETTER | UNDERSCORE) VAR_CHAR*;

	let NUMBER = DIGIT DIGIT*;
	let INT = '-'? NUMBER;
	// TODO exact definition of float in twee
	let FLOAT = (INT "." NUMBER?) | ("." NUMBER);

	let STRING = ('"' [^'"']* '"') | ("'" [^"'"]* "'");

	let SET = "set";
	let ASSIGN = "=" | "to";
	let IF = "if";
	let ELSE = "else";
	let END_IF = "endif";

	let NUM_OP = ["+-*/%"];
	let COMP_OP = "is" | "==" | "eq" | "neq" | ">" | "gt" | ">=" | "gte" | "<" | "lt" | "<=" | "lte";
	let LOG_OP = "and" | "or" | "not";

	INITIAL {
		PASSAGE_START => |lexer:&mut TweeLexer<R>| -> Option<Token>{
			lexer.PASSAGE();
			None
		}

		MAKRO_START => |lexer:&mut TweeLexer<R>| {
			lexer.MAKRO();
			Some(TokMakroStart)
		}

		LINK_SIMPLE =>  |lexer:&mut TweeLexer<R>| {
			let s =  lexer.yystr();
			let trimmed = &s[2 .. s.len()-2];
			let name = &trimmed.to_string();
			Some(TokPassageLink(name.clone(), name.clone()))
		}

		LINK_LABELED =>  |lexer:&mut TweeLexer<R>| {
			let s =  lexer.yystr();
			let trimmed = &s[2 .. s.len()-2];
			let matches = &trimmed.split("|").collect::<Vec<&str>>();
			assert_eq!(matches.len(), 2);
			let text = matches[0].to_string();
			let name = matches[1].to_string();
			Some(TokPassageLink(text, name))
		}

		FORMAT_ITALIC => |_:&mut TweeLexer<R>| Some(TokFormatItalic)
		FORMAT_BOLD => |_:&mut TweeLexer<R>| Some(TokFormatBold)
		FORMAT_UNDER => |_:&mut TweeLexer<R>| Some(TokFormatUnder)
		FORMAT_STRIKE => |_:&mut TweeLexer<R>| Some(TokFormatStrike)
		FORMAT_SUB => |_:&mut TweeLexer<R>| Some(TokFormatSub)
		FORMAT_SUP => |_:&mut TweeLexer<R>| Some(TokFormatSup)
		FORMAT_MONO_START => |_:&mut TweeLexer<R>| Some(TokFormatMonoStart)
		FORMAT_MONO_END => |_:&mut TweeLexer<R>| Some(TokFormatMonoEnd)
		FORMAT_BUL_LIST =>  |_:&mut TweeLexer<R>| Some(TokFormatBulList)
		FORMAT_NUMB_LIST =>  |_:&mut TweeLexer<R>| Some(TokFormatNumbList)
		FORMAT_INDENT  =>  |_:&mut TweeLexer<R>| Some(TokFormatIndent)
		FORMAT_DOUBLE_INDENT  =>  |_:&mut TweeLexer<R>| Some(TokFormatIndentDouble)
		FORMAT_INDENT_BLOCK  =>  |_:&mut TweeLexer<R>| Some(TokFormatIndentBlock)
		FORMAT_HEADING  =>  |lexer:&mut TweeLexer<R>| Some(TokFormatHeading(lexer.yystr().len()))

		TEXTLINES => |lexer:&mut TweeLexer<R>| Some(TokText(lexer.yystr()))
	}

	PASSAGE {
		PASSAGE_NAME => |lexer:&mut TweeLexer<R>| Some(TokPassageName(lexer.yystr().trim().to_string()))
		TAG_START => |lexer:&mut TweeLexer<R>| {
			lexer.TAGS();
			Some(TokTagStart)
		}
		NEWLINE => |lexer:&mut TweeLexer<R>| -> Option<Token>{
			lexer.INITIAL();
			None
		}
	}

	TAGS {
		WORD => |lexer:&mut TweeLexer<R>| Some(TokTag(lexer.yystr()))
		TAG_END => |lexer:&mut TweeLexer<R>| {
			lexer.PASSAGE();
			Some(TokTagEnd)
		}
	}

	MAKRO {
		MAKRO_END => |lexer:&mut TweeLexer<R>| {
			lexer.INITIAL();
			Some(TokMakroEnd)
		}
		VAR_NAME =>  |lexer:&mut TweeLexer<R>| Some(TokVariable(lexer.yystr()))
		FLOAT =>  |lexer:&mut TweeLexer<R>| Some(TokFloat(lexer.yystr()[..].parse().unwrap()))
		INT =>  |lexer:&mut TweeLexer<R>| Some(TokInt(lexer.yystr()[..].parse().unwrap()))
		STRING =>  |lexer:&mut TweeLexer<R>| Some(TokString(lexer.yystr()))
		SET =>  |_:&mut TweeLexer<R>| Some(TokSet)
		ASSIGN =>  |_:&mut TweeLexer<R>| Some(TokAssign)
		IF =>  |_:&mut TweeLexer<R>| Some(TokIf)
		ELSE =>  |_:&mut TweeLexer<R>| Some(TokElse)
		END_IF =>  |_:&mut TweeLexer<R>| Some(TokEndIf)
		NUM_OP =>  |lexer:&mut TweeLexer<R>| Some(TokNumOp(lexer.yystr()))
		COMP_OP =>  |lexer:&mut TweeLexer<R>| Some(TokCompOp(lexer.yystr()))
		LOG_OP =>  |lexer:&mut TweeLexer<R>| Some(TokLogOp(lexer.yystr()))
		BR_OPEN =>  |_:&mut TweeLexer<R>| Some(TokBracketOpen)
		BR_CLOSE =>  |_:&mut TweeLexer<R>| Some(TokBracketClose)
	}

}

#[test]
fn it_works() {

}
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::io;
use std::net::SocketAddr;

use serde::{Deserialize, Serialize};
use serde_yaml::Error;

/// Config is the configuration for either a sender or a receiver
#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
    pub local: Local,
    #[serde(flatten)]
    pub connections: ConnectionConfig,
}

/// Local is the local host configuration options
#[derive(Debug, Deserialize, Serialize)]
pub struct Local {
    pub port: u16,
}

/// ConnectionConfig is the configuration for either a sender or receivers
#[derive(Debug, Deserialize, Serialize)]
pub enum ConnectionConfig {
    /// SenderConfig is the configuration for the sender, such as when sitting behind a game client.
    #[serde(rename = "sender_config")]
    Sender {
        address: SocketAddr,
        connection_id: String,
    },

    /// Receiver is the configuration for a recievers, such as a proxy that sits in front of a
    /// set of Dedicated Game Servers.
    #[serde(rename = "receiver_config")]
    Receiver { endpoints: Vec<EndPoint> },
}

/// A singular endpoint, to pass on UDP packets to.
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct EndPoint {
    pub name: String,
    pub address: SocketAddr,
    pub connection_ids: Vec<String>,
}

/// from_reader returns a config from a given Reader
pub fn from_reader<R: io::Read>(input: R) -> Result<Config, Error> {
    let config: Config = serde_yaml::from_reader(input)?;
    return Ok(config);
}

#[cfg(test)]
mod tests {
    use crate::config::{from_reader, Config, ConnectionConfig, EndPoint, Local};

    #[test]
    fn deserialise_sender() {
        let config = Config {
            local: Local { port: 7000 },
            connections: ConnectionConfig::Sender {
                address: "127.0.0.1:25999".parse().unwrap(),
                connection_id: String::from("1234"),
            },
        };
        let yaml = serde_yaml::to_string(&config).unwrap();
        println!("{}", yaml);
    }

    #[test]
    fn deserialise_reciever() {
        let config = Config {
            local: Local { port: 7000 },
            connections: ConnectionConfig::Receiver {
                endpoints: vec![
                    EndPoint {
                        name: String::from("No.1"),
                        address: "127.0.0.1:26000".parse().unwrap(),
                        connection_ids: vec![String::from("1234"), String::from("5678")],
                    },
                    EndPoint {
                        name: String::from("No.2"),
                        address: "127.0.0.1:26001".parse().unwrap(),
                        connection_ids: vec![String::from("1234")],
                    },
                ],
            },
        };
        let yaml = serde_yaml::to_string(&config).unwrap();
        println!("{}", yaml);
    }

    #[test]
    fn parse_sender() {
        let yaml = "
local:
  port: 7000
sender_config:
  address: 127.0.0.1:25999
  connection_id: 1x7ijy6";
        let config = from_reader(yaml.as_bytes()).unwrap();
        assert_eq!(7000, config.local.port);
        match config.connections {
            ConnectionConfig::Sender {
                address,
                connection_id,
            } => {
                assert_eq!("1x7ijy6", connection_id);
                assert_eq!("127.0.0.1:25999", address.to_string())
            }
            ConnectionConfig::Receiver { .. } => panic!("Should not be a receiver"),
        }
    }

    #[test]
    fn parse_receiver() {
        let yaml = "
---
local:
  port: 7000
receiver_config:
  endpoints:
    - name: Game Server No. 1
      address: 127.0.0.1:26000
      connection_ids:
        - 1x7ijy6
        - 8gj3v2i
    - name: Game Server No. 2
      address: 127.0.0.1:26001
      connection_ids:
        - nkuy70x";
        let config = from_reader(yaml.as_bytes()).unwrap();
        assert_eq!(7000, config.local.port);
        match config.connections {
            ConnectionConfig::Sender { .. } => panic!("Should not be a sender"),
            ConnectionConfig::Receiver { endpoints } => {
                let expected = vec![
                    EndPoint {
                        name: String::from("Game Server No. 1"),
                        address: "127.0.0.1:26000".parse().unwrap(),
                        connection_ids: vec![String::from("1x7ijy6"), String::from("8gj3v2i")],
                    },
                    EndPoint {
                        name: String::from("Game Server No. 2"),
                        address: "127.0.0.1:26001".parse().unwrap(),
                        connection_ids: vec![String::from("nkuy70x")],
                    },
                ];
                assert_eq!(expected, endpoints);
            }
        }
    }
}
<commit_msg>Fix typo<commit_after>/*
 * Copyright 2020 Google LLC All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::io;
use std::net::SocketAddr;

use serde::{Deserialize, Serialize};
use serde_yaml::Error;

/// Config is the configuration for either a sender or a receiver
#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
    pub local: Local,
    #[serde(flatten)]
    pub connections: ConnectionConfig,
}

/// Local is the local host configuration options
#[derive(Debug, Deserialize, Serialize)]
pub struct Local {
    pub port: u16,
}

/// ConnectionConfig is the configuration for either a sender or receivers
#[derive(Debug, Deserialize, Serialize)]
pub enum ConnectionConfig {
    /// SenderConfig is the configuration for the sender, such as when sitting behind a game client.
    #[serde(rename = "sender_config")]
    Sender {
        address: SocketAddr,
        connection_id: String,
    },

    /// Receiver is the configuration for a recievers, such as a proxy that sits in front of a
    /// set of Dedicated Game Servers.
    #[serde(rename = "receiver_config")]
    Receiver { endpoints: Vec<EndPoint> },
}

/// A singular endpoint, to pass on UDP packets to.
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct EndPoint {
    pub name: String,
    pub address: SocketAddr,
    pub connection_ids: Vec<String>,
}

/// from_reader returns a config from a given Reader
pub fn from_reader<R: io::Read>(input: R) -> Result<Config, Error> {
    let config: Config = serde_yaml::from_reader(input)?;
    return Ok(config);
}

#[cfg(test)]
mod tests {
    use crate::config::{from_reader, Config, ConnectionConfig, EndPoint, Local};

    #[test]
    fn deserialise_sender() {
        let config = Config {
            local: Local { port: 7000 },
            connections: ConnectionConfig::Sender {
                address: "127.0.0.1:25999".parse().unwrap(),
                connection_id: String::from("1234"),
            },
        };
        let yaml = serde_yaml::to_string(&config).unwrap();
        println!("{}", yaml);
    }

    #[test]
    fn deserialise_receiver() {
        let config = Config {
            local: Local { port: 7000 },
            connections: ConnectionConfig::Receiver {
                endpoints: vec![
                    EndPoint {
                        name: String::from("No.1"),
                        address: "127.0.0.1:26000".parse().unwrap(),
                        connection_ids: vec![String::from("1234"), String::from("5678")],
                    },
                    EndPoint {
                        name: String::from("No.2"),
                        address: "127.0.0.1:26001".parse().unwrap(),
                        connection_ids: vec![String::from("1234")],
                    },
                ],
            },
        };
        let yaml = serde_yaml::to_string(&config).unwrap();
        println!("{}", yaml);
    }

    #[test]
    fn parse_sender() {
        let yaml = "
local:
  port: 7000
sender_config:
  address: 127.0.0.1:25999
  connection_id: 1x7ijy6";
        let config = from_reader(yaml.as_bytes()).unwrap();
        assert_eq!(7000, config.local.port);
        match config.connections {
            ConnectionConfig::Sender {
                address,
                connection_id,
            } => {
                assert_eq!("1x7ijy6", connection_id);
                assert_eq!("127.0.0.1:25999", address.to_string())
            }
            ConnectionConfig::Receiver { .. } => panic!("Should not be a receiver"),
        }
    }

    #[test]
    fn parse_receiver() {
        let yaml = "
---
local:
  port: 7000
receiver_config:
  endpoints:
    - name: Game Server No. 1
      address: 127.0.0.1:26000
      connection_ids:
        - 1x7ijy6
        - 8gj3v2i
    - name: Game Server No. 2
      address: 127.0.0.1:26001
      connection_ids:
        - nkuy70x";
        let config = from_reader(yaml.as_bytes()).unwrap();
        assert_eq!(7000, config.local.port);
        match config.connections {
            ConnectionConfig::Sender { .. } => panic!("Should not be a sender"),
            ConnectionConfig::Receiver { endpoints } => {
                let expected = vec![
                    EndPoint {
                        name: String::from("Game Server No. 1"),
                        address: "127.0.0.1:26000".parse().unwrap(),
                        connection_ids: vec![String::from("1x7ijy6"), String::from("8gj3v2i")],
                    },
                    EndPoint {
                        name: String::from("Game Server No. 2"),
                        address: "127.0.0.1:26001".parse().unwrap(),
                        connection_ids: vec![String::from("nkuy70x")],
                    },
                ];
                assert_eq!(expected, endpoints);
            }
        }
    }
}
<|endoftext|>


<commit_before>use error::Result;
use std::fmt::Debug;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use toml;

#[derive(Serialize, Deserialize, Debug)]
pub struct Config {
    pub force: Option<bool>,
    pub in_dir: Option<String>,
    pub out_dir: Option<String>,
    pub port: Option<u16>,
    pub title: String,
}

impl Default for Config {
    fn default() -> Self {
        Config {
            force: None,
            in_dir: None,
            out_dir: None,
            port: None,
            title: "Default Title".to_string(),
        }
    }
}

impl Config {
    pub fn from_file<P>(path: P) -> Result<Self>
            where P: AsRef<Path> + Debug {
        let mut reader = File::open(&path)
            .map_err(|e| format!("open {:?} failed: {}", path, e))?;
        let mut conf = vec![];
        reader.read_to_end(&mut conf)
              .map_err(|e| format!("reading config file failed: {}", e))?;
        let config = toml::from_slice(conf.as_slice())
            .map_err(|e| format!("parse config file failed: {}", e))?;

        Ok(config)
    }
}
<commit_msg>Add unit test for config<commit_after>use error::Result;
use std::fmt::Debug;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use toml;

#[derive(Serialize, Deserialize, Debug)]
pub struct Config {
    pub force: Option<bool>,
    pub in_dir: Option<String>,
    pub out_dir: Option<String>,
    pub port: Option<u16>,
    pub title: String,
}

impl Default for Config {
    fn default() -> Self {
        Config {
            force: None,
            in_dir: None,
            out_dir: None,
            port: None,
            title: "Default Title".to_string(),
        }
    }
}

impl Config {
    pub fn from_file<P>(path: P) -> Result<Self>
            where P: AsRef<Path> + Debug {
        let mut reader = File::open(&path)
            .map_err(|e| format!("open {:?} failed: {}", path, e))?;
        let mut conf = vec![];
        reader.read_to_end(&mut conf)
              .map_err(|e| format!("reading config file failed: {}", e))?;
        let config = toml::from_slice(conf.as_slice())
            .map_err(|e| format!("parse config file failed: {}", e))?;

        Ok(config)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ::std::{env, fs};
    use ::std::io::Write;

    #[test]
    fn test_read_config() {
        let p = env::temp_dir().join("config.test");
        let mut f = File::create(&p).unwrap();
        f.write(b"force = true\n\
                  in_dir = \".\"\n\
                  port = 9999\n\
                  title = \"title\"").unwrap();

        let c = Config::from_file(&p).unwrap();
        assert!(c.force == Some(true));
        assert!(c.in_dir == Some(".".to_string()));
        assert!(c.out_dir == None);
        assert!(c.port == Some(9999));
        assert!(c.title == "title".to_string());

        fs::remove_file(p).unwrap();
    }
}
<|endoftext|>


<commit_before>/// The Toml Delete extensions

use toml::Value;

use tokenizer::Token;
use tokenizer::tokenize_with_seperator;
use error::*;

pub trait TomlValueDeleteExt {

    /// Extension function for deleting a value in the current toml::Value document
    /// using a custom seperator.
    ///
    /// # Semantics
    ///
    /// The function does _not_ delete non-empty data structures. So deleting `array` from
    ///
    /// ```toml
    /// array = [ 1 ]
    /// ```
    ///
    /// does _not_ work.
    ///
    /// # Return value
    ///
    /// If the delete operation worked correctly, `Ok(Option<Value>)` is returned.
    ///
    /// The `Option<Value>` part is `None` if no value was actually removed as there was no value
    /// there. For example, if you're deleting `table.a` and the Table `table` has no key `a`, then
    /// `Ok(None)` is returned. Also, if you're deleting from an Array, but there is nothing in the
    /// array, or the array is shorter than the index you're deleting.
    /// If the delete operation actually removed something from the toml document, this value is
    /// returned as `Ok(Some(Value))`.
    ///
    /// On failure, `Err(e)` is returned
    ///
    fn delete_with_seperator(&mut self, query: &String, sep: char) -> Result<Option<Value>>;

    /// Extension function for inserting a value from the current toml::Value document
    ///
    /// See documentation of `TomlValueinsertExt::insert_with_seperator`
    fn delete(&mut self, query: &String) -> Result<Option<Value>> {
        self.delete_with_seperator(query, '.')
    }

}

impl TomlValueDeleteExt for Value {

    fn delete_with_seperator(&mut self, query: &String, sep: char) -> Result<Option<Value>> {
        use resolver::mut_resolver::resolve;

        unimplemented!()
    }

}

#[cfg(test)]
mod test {
    use super::*;
    use error::*;
    use toml::Value;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_delete_from_empty_document() {
        let mut toml : Value = toml_from_str("").unwrap();

        let res = toml.delete_with_seperator(&String::from("a"), '.');

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());
    }

    #[test]
    fn test_delete_from_empty_table() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let res = toml.delete_with_seperator(&String::from("table.a"), '.');

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());
    }

    #[test]
    fn test_delete_integer() {
        let mut toml : Value = toml_from_str(r#"
        value = 1
        "#).unwrap();

        let res = toml.delete_with_seperator(&String::from("value"), '.');

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(1)));
    }

    #[test]
    fn test_delete_string() {
        let mut toml : Value = toml_from_str(r#"
        value = "foo"
        "#).unwrap();

        let res = toml.delete_with_seperator(&String::from("value"), '.');

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::String(_)));
        match res {
            Value::String(ref s) => assert_eq!("foo", s),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_delete_empty_table() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let res = toml.delete_with_seperator(&String::from("table"), '.');

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Table(_)));
        match res {
            Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_delete_empty_array() {
        let mut toml : Value = toml_from_str(r#"
        array = []
        "#).unwrap();

        let res = toml.delete_with_seperator(&String::from("array"), '.');

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Array(_)));
        match res {
            Value::Array(ref a) => assert!(a.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

}

<commit_msg>Add some error tests<commit_after>/// The Toml Delete extensions

use toml::Value;

use tokenizer::Token;
use tokenizer::tokenize_with_seperator;
use error::*;

pub trait TomlValueDeleteExt {

    /// Extension function for deleting a value in the current toml::Value document
    /// using a custom seperator.
    ///
    /// # Semantics
    ///
    /// The function does _not_ delete non-empty data structures. So deleting `array` from
    ///
    /// ```toml
    /// array = [ 1 ]
    /// ```
    ///
    /// does _not_ work.
    ///
    /// # Return value
    ///
    /// If the delete operation worked correctly, `Ok(Option<Value>)` is returned.
    ///
    /// The `Option<Value>` part is `None` if no value was actually removed as there was no value
    /// there. For example, if you're deleting `table.a` and the Table `table` has no key `a`, then
    /// `Ok(None)` is returned. Also, if you're deleting from an Array, but there is nothing in the
    /// array, or the array is shorter than the index you're deleting.
    /// If the delete operation actually removed something from the toml document, this value is
    /// returned as `Ok(Some(Value))`.
    ///
    /// On failure, `Err(e)` is returned
    ///
    fn delete_with_seperator(&mut self, query: &String, sep: char) -> Result<Option<Value>>;

    /// Extension function for inserting a value from the current toml::Value document
    ///
    /// See documentation of `TomlValueinsertExt::insert_with_seperator`
    fn delete(&mut self, query: &String) -> Result<Option<Value>> {
        self.delete_with_seperator(query, '.')
    }

}

impl TomlValueDeleteExt for Value {

    fn delete_with_seperator(&mut self, query: &String, sep: char) -> Result<Option<Value>> {
        use resolver::mut_resolver::resolve;

        unimplemented!()
    }

}

#[cfg(test)]
mod test {
    use super::*;
    use error::*;
    use toml::Value;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_delete_from_empty_document() {
        let mut toml : Value = toml_from_str("").unwrap();

        let res = toml.delete_with_seperator(&String::from("a"), '.');

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());
    }

    #[test]
    fn test_delete_from_empty_table() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let res = toml.delete_with_seperator(&String::from("table.a"), '.');

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());
    }

    #[test]
    fn test_delete_integer() {
        let mut toml : Value = toml_from_str(r#"
        value = 1
        "#).unwrap();

        let res = toml.delete_with_seperator(&String::from("value"), '.');

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(1)));
    }

    #[test]
    fn test_delete_string() {
        let mut toml : Value = toml_from_str(r#"
        value = "foo"
        "#).unwrap();

        let res = toml.delete_with_seperator(&String::from("value"), '.');

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::String(_)));
        match res {
            Value::String(ref s) => assert_eq!("foo", s),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_delete_empty_table() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let res = toml.delete_with_seperator(&String::from("table"), '.');

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Table(_)));
        match res {
            Value::Table(ref t) => assert!(t.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_delete_empty_array() {
        let mut toml : Value = toml_from_str(r#"
        array = []
        "#).unwrap();

        let res = toml.delete_with_seperator(&String::from("array"), '.');

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Array(_)));
        match res {
            Value::Array(ref a) => assert!(a.is_empty()),
            _ => panic!("What just happened?"),
        }
    }

    #[test]
    fn test_delete_nonempty_table() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        a = 1
        "#).unwrap();

        let res = toml.delete_with_seperator(&String::from("table"), '.');

        assert!(res.is_err());

        let res = res.unwrap_err();
        assert!(is_match!(res.kind(), &ErrorKind::CannotDeleteNonEmptyTable(_)));
    }

    #[test]
    fn test_delete_nonempty_array() {
        let mut toml : Value = toml_from_str(r#"
        array = [ 1 ]
        "#).unwrap();

        let res = toml.delete_with_seperator(&String::from("array.[0]"), '.');

        assert!(res.is_err());

        let res = res.unwrap_err();
        assert!(is_match!(res.kind(), &ErrorKind::CannotDeleteNonEmptyArray(_)));
    }

}

<|endoftext|>


<commit_before>use term_painter::ToStyle;
use term_painter::Attr::*;
use std::fmt;
use std::io;
use std::process;

#[derive(Clone)]
pub struct SearchResult {
    pub title: String,
    pub score: String,
    pub number: String,
    pub genres: Vec<String>,
    pub year: String,
}

impl fmt::Display for SearchResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f,
                    "{}",
                    Bold.paint(format!("{} ({})\n", &self.title, &self.year))));
        let mut stars = String::new();
        let score: f32 = self.score.parse::<f32>().unwrap();
        for i in 0..10 {
            if i < (score + 0.5) as i32 {
                stars.push_str("\u{2605}");
            } else {
                stars.push_str("\u{2606}");
            }
        }
        try!(write!(f, "{}", &self.genres[0]));
        for genre in self.genres.clone().into_iter().skip(1) {
            try!(write!(f, ", {}", genre));
        }
        write!(f,
               "\n{}, ({} bei {} Bewertungen)",
               stars,
               &self.score,
               &self.number)
    }
}

impl fmt::Debug for SearchResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{:?}\n{:?}\n{:?}\n{:?}\n{:?}\n******",
               self.title,
               self.year,
               self.genres,
               self.score,
               self.number)
    }
}

pub fn output_result(results: Vec<SearchResult>) {
    let further = results.clone();
    for res in results.into_iter().take(3) {
        println!("{}", res);
    }
    for output in further.into_iter().skip(3) {
        let mut buffer = String::new();
        io::stdin().read_line(&mut buffer);
        if buffer != "q\n" {
            println!("{}", output);
        } else {
            process::exit(0);
        }
    }
}
<commit_msg>fixed unused result<commit_after>use term_painter::ToStyle;
use term_painter::Attr::*;
use std::fmt;
use std::io;
use std::process;

#[derive(Clone)]
pub struct SearchResult {
    pub title: String,
    pub score: String,
    pub number: String,
    pub genres: Vec<String>,
    pub year: String,
}

impl fmt::Display for SearchResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f,
                    "{}",
                    Bold.paint(format!("{} ({})\n", &self.title, &self.year))));
        let mut stars = String::new();
        let score: f32 = self.score.parse::<f32>().unwrap();
        for i in 0..10 {
            if i < (score + 0.5) as i32 {
                stars.push_str("\u{2605}");
            } else {
                stars.push_str("\u{2606}");
            }
        }
        try!(write!(f, "{}", &self.genres[0]));
        for genre in self.genres.clone().into_iter().skip(1) {
            try!(write!(f, ", {}", genre));
        }
        write!(f,
               "\n{}, ({} bei {} Bewertungen)",
               stars,
               &self.score,
               &self.number)
    }
}

impl fmt::Debug for SearchResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{:?}\n{:?}\n{:?}\n{:?}\n{:?}\n******",
               self.title,
               self.year,
               self.genres,
               self.score,
               self.number)
    }
}

pub fn output_result(results: Vec<SearchResult>) {
    let further = results.clone();
    for res in results.into_iter().take(3) {
        println!("{}", res);
    }
    for output in further.into_iter().skip(3) {
        let mut buffer = String::new();
        if io::stdin().read_line(&mut buffer).is_ok() {
            if buffer != "q\n" {
                println!("{}", output);
            } else {
                process::exit(0);
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 David Stainton <dstainton415@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! TCP packet abstraction

use packet::Packet;
use packet::HasPseudoheader;
use packet::checksum::rfc1071_checksum;
use pnet_macros::types::*;

/// Represents a TCP Packet
#[packet]
pub struct Tcp {
    source: u16be,
    destination: u16be,
    sequence: u32be,
    acknowledgement: u32be,
    data_offset_and_reserved: u8,
    control_bits: u8,
    window: u16be,
    checksum: u16be,
    urgent_pointer: u16be,
    #[length_fn = "tcp_options_length"]
    options: Vec<TcpOptions>,
    #[length_fn = "tcp_padding_length"]
    padding: Vec<TcpPadding>,
    #[payload]
    payload: Vec<u8>
}

fn tcp_options_length<'a>(tcp: &TcpPacket<'a>) -> usize {
    /* The data offset field specifies the total size of the TCP header
       in 32-bit words. The minimum size of a TCP header is 20 bytes and thus
       TCP headers must have data offset set to 5 or more.
     */
    let mut v = tcp.get_data_offset_and_reserved();
    v  = v >> 4; // get rid of reserved bits
    v = v - 5; // remove the size of the minal tcp header of 20 bytes
    v = v * 4; // multiple the remaining word count by 4 to get the byte count
    return v as usize;
}

/// Represents the TCP Option fields
#[packet]
pub struct TcpOptions {
    kind: u8,
    #[payload]
    data: Vec<u8>
}

fn tcp_padding_length<'a>(tcp: &TcpPacket<'a>) -> usize {
    /* The TCP header padding is used to ensure that the entire header
       ends on a 32 bit boundary.
     */
    return tcp.get_data_offset_and_reserved() as usize % 4;
}

/// Represents the TCP header padding
#[packet]
pub struct TcpPadding {
    #[payload]
    data: Vec<u8>
}

/// Calculates the checksum of a TCP packet
/// The passed in TcpPacket must have it's initial checksum value set to zero.
pub fn checksum<'a, T: HasPseudoheader>(packet: &TcpPacket<'a>, encapsulating_packet: T) -> u16be {
    let mut sum = encapsulating_packet.pseudoheader_checksum();
    let length = packet.packet().len() as u32;
    sum = sum + length & 0xffff;
    sum = sum + length >> 16;
    return rfc1071_checksum(packet.packet(), sum);
}

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

    const TCP_MIN_HEADER_LEN: usize = 20;
    const TCP_OPTIONS_LEN: usize = 12;
    const PAYLOAD_LEN: usize = 5;

    #[test]
    fn tcp_header_ipv4_test() {
        use pnet::packet::ip::IpNextHeaderProtocols;
        use pnet::packet::ipv4::{Ipv4Packet,MutableIpv4Packet};
        use std::net::{Ipv4Addr};

        const IPV4_HEADER_LEN: usize = 20;

        let mut packet = [0u8; IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + PAYLOAD_LEN];
        let ipv4_source = Ipv4Addr::new(127, 0, 0, 1);
        let ipv4_destination = Ipv4Addr::new(127, 0, 0, 1);
        let next_level_protocol = IpNextHeaderProtocols::Tcp;
        let mut csum = 0;

        {
            let mut mut_ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
            mut_ip_header.set_next_level_protocol(next_level_protocol);
            mut_ip_header.set_source(ipv4_source);
            mut_ip_header.set_destination(ipv4_destination);
        }

        {
            let mut mutable_tcp_header = MutableTcpPacket::new(&mut packet[IPV4_HEADER_LEN..]).unwrap();
            mutable_tcp_header.set_checksum(0);
        }

        {
            let ip_header = Ipv4Packet::new(&packet[..IPV4_HEADER_LEN]).unwrap();
            let tcp_header = TcpPacket::new(&packet[IPV4_HEADER_LEN..]).unwrap();
            csum = checksum(&tcp_header, ip_header);
        }

        {
            let mut mutable_tcp_header = MutableTcpPacket::new(&mut packet[IPV4_HEADER_LEN..]).unwrap();
            mutable_tcp_header.set_checksum(csum);
        }

        {
            generate_simple_tcp_header(&mut packet[IPV4_HEADER_LEN..]);
        }

        // Set payload data
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 0] = 'm' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 1] = 'e' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 2] = 'o' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 3] = 'w' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 4] = '\n' as u8;

        let ref_tcp_packet = [0xe0, 0x0f, // source port
                              0x25, 0xc2, // dest port
                              0xdf, 0x06, // sequence
                              0xe6, 0xe6,
                              0xc9, 0x2d, // acknowledgement
                              0x98, 0x71,
                              0x80,       // header length + reserved
                              0x18,       // control bits
                              0x02, 0xab, // window
                              0xfe, 0x2d, // checksum
                              0x00, 0x00, // urgent pointer
                              0x01, 0x01, // tcp option no-op
                              0x08, 0x0a, // tcp option timestamp, options length == 10 bytes
                              0x1d, 0xfc, // 4-byte send timestamp
                              0xcb, 0x76,
                              0x1d, 0xfc, // 4-byte latest replied timestamp
                              0xbe, 0x62,
                              0x6d, 0x65, // payload
                              0x6f, 0x77, 0x0a];
        assert_eq!(&ref_tcp_packet[..], &packet[IPV4_HEADER_LEN..]);

        //tcp/ipv4 == "45, 00 00 39 58 89 40 00 40 06 e4 33 7f 00 00 01 7f 00 00 01 e0 0f 25 c2 df 06 e6 e6 c9 2d 98 71 80 18 02 ab fe 2d 00 00 01 01 08 0a 1d fc cb 76 1d fc be 62 6d 65 6f 77 0a";

    }

    fn generate_simple_tcp_header<'p>(packet: &'p mut [u8]) {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[..]).unwrap();
        tcp_header.set_source(57359);
        assert_eq!(tcp_header.get_source(), 57359);

        tcp_header.set_destination(9666);
        assert_eq!(tcp_header.get_destination(), 9666);

        tcp_header.set_sequence(3741771494);
        assert_eq!(tcp_header.get_sequence(), 3741771494);

        tcp_header.set_acknowledgement(3375208561);
        assert_eq!(tcp_header.get_acknowledgement(), 3375208561);

        tcp_header.set_data_offset_and_reserved(0x80);
        assert_eq!(tcp_header.get_data_offset_and_reserved(), 0x80);

        tcp_header.set_control_bits(0x18);
        assert_eq!(tcp_header.get_control_bits(), 0x18);

        tcp_header.set_window(0x02ab);
        assert_eq!(tcp_header.get_window(), 0x02ab);

        tcp_header.set_checksum(0xfe2d);
        assert_eq!(tcp_header.get_checksum(), 0xfe2d);

        tcp_header.set_urgent_pointer(0x0000);
        assert_eq!(tcp_header.get_urgent_pointer(), 0x0000);

        let mut opts: Vec<TcpOptions> = Vec::new();
        let tcp_option = TcpOptions{
            kind: 0x1,
            data: vec![0x01,0x08,0x0a,0x1d,0xfc,0xcb,0x76,0x1d,0xfc,0xbe,0x62],
        };
        opts.push(tcp_option);
        tcp_header.set_options(opts);
    }
}
<commit_msg>use vec![]; instead of constructor method<commit_after>// Copyright (c) 2015 David Stainton <dstainton415@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! TCP packet abstraction

use packet::Packet;
use packet::HasPseudoheader;
use packet::checksum::rfc1071_checksum;
use pnet_macros::types::*;

/// Represents a TCP Packet
#[packet]
pub struct Tcp {
    source: u16be,
    destination: u16be,
    sequence: u32be,
    acknowledgement: u32be,
    data_offset_and_reserved: u8,
    control_bits: u8,
    window: u16be,
    checksum: u16be,
    urgent_pointer: u16be,
    #[length_fn = "tcp_options_length"]
    options: Vec<TcpOptions>,
    #[length_fn = "tcp_padding_length"]
    padding: Vec<TcpPadding>,
    #[payload]
    payload: Vec<u8>
}

fn tcp_options_length<'a>(tcp: &TcpPacket<'a>) -> usize {
    /* The data offset field specifies the total size of the TCP header
       in 32-bit words. The minimum size of a TCP header is 20 bytes and thus
       TCP headers must have data offset set to 5 or more.
     */
    let mut v = tcp.get_data_offset_and_reserved();
    v  = v >> 4; // get rid of reserved bits
    v = v - 5; // remove the size of the minimal tcp header of 20 bytes
    v = v * 4; // multiple the remaining word count by 4 to get the byte count
    return v as usize;
}

/// Represents the TCP Option fields
#[packet]
pub struct TcpOptions {
    kind: u8,
    #[payload]
    data: Vec<u8>
}

fn tcp_padding_length<'a>(tcp: &TcpPacket<'a>) -> usize {
    /* The TCP header padding is used to ensure that the entire header
       ends on a 32 bit boundary.
     */
    return tcp.get_data_offset_and_reserved() as usize % 4;
}

/// Represents the TCP header padding
#[packet]
pub struct TcpPadding {
    #[payload]
    data: Vec<u8>
}

/// Calculates the checksum of a TCP packet
/// The passed in TcpPacket must have it's initial checksum value set to zero.
pub fn checksum<'a, T: HasPseudoheader>(packet: &TcpPacket<'a>, encapsulating_packet: T) -> u16be {
    let mut sum = encapsulating_packet.pseudoheader_checksum();
    let length = packet.packet().len() as u32;
    sum = sum + length & 0xffff;
    sum = sum + length >> 16;
    return rfc1071_checksum(packet.packet(), sum);
}

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

    const TCP_MIN_HEADER_LEN: usize = 20;
    const TCP_OPTIONS_LEN: usize = 12;
    const PAYLOAD_LEN: usize = 5;

    #[test]
    fn tcp_header_ipv4_test() {
        use pnet::packet::ip::IpNextHeaderProtocols;
        use pnet::packet::ipv4::{Ipv4Packet,MutableIpv4Packet};
        use std::net::{Ipv4Addr};

        const IPV4_HEADER_LEN: usize = 20;

        let mut packet = [0u8; IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + PAYLOAD_LEN];
        let ipv4_source = Ipv4Addr::new(127, 0, 0, 1);
        let ipv4_destination = Ipv4Addr::new(127, 0, 0, 1);
        let next_level_protocol = IpNextHeaderProtocols::Tcp;
        let mut csum = 0;

        {
            let mut mut_ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
            mut_ip_header.set_next_level_protocol(next_level_protocol);
            mut_ip_header.set_source(ipv4_source);
            mut_ip_header.set_destination(ipv4_destination);
        }

        {
            let mut mutable_tcp_header = MutableTcpPacket::new(&mut packet[IPV4_HEADER_LEN..]).unwrap();
            mutable_tcp_header.set_checksum(0);
        }

        {
            let ip_header = Ipv4Packet::new(&packet[..IPV4_HEADER_LEN]).unwrap();
            let tcp_header = TcpPacket::new(&packet[IPV4_HEADER_LEN..]).unwrap();
            csum = checksum(&tcp_header, ip_header);
        }

        {
            let mut mutable_tcp_header = MutableTcpPacket::new(&mut packet[IPV4_HEADER_LEN..]).unwrap();
            mutable_tcp_header.set_checksum(csum);
        }

        {
            generate_simple_tcp_header(&mut packet[IPV4_HEADER_LEN..]);
        }

        // Set payload data
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 0] = 'm' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 1] = 'e' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 2] = 'o' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 3] = 'w' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 4] = '\n' as u8;

        let ref_tcp_packet = [0xe0, 0x0f, // source port
                              0x25, 0xc2, // dest port
                              0xdf, 0x06, // sequence
                              0xe6, 0xe6,
                              0xc9, 0x2d, // acknowledgement
                              0x98, 0x71,
                              0x80,       // header length + reserved
                              0x18,       // control bits
                              0x02, 0xab, // window
                              0xfe, 0x2d, // checksum
                              0x00, 0x00, // urgent pointer
                              0x01, 0x01, // tcp option no-op
                              0x08, 0x0a, // tcp option timestamp, options length == 10 bytes
                              0x1d, 0xfc, // 4-byte send timestamp
                              0xcb, 0x76,
                              0x1d, 0xfc, // 4-byte latest replied timestamp
                              0xbe, 0x62,
                              0x6d, 0x65, // payload
                              0x6f, 0x77, 0x0a];
        assert_eq!(&ref_tcp_packet[..], &packet[IPV4_HEADER_LEN..]);

        //tcp/ipv4 == "45, 00 00 39 58 89 40 00 40 06 e4 33 7f 00 00 01 7f 00 00 01 e0 0f 25 c2 df 06 e6 e6 c9 2d 98 71 80 18 02 ab fe 2d 00 00 01 01 08 0a 1d fc cb 76 1d fc be 62 6d 65 6f 77 0a";

    }

    fn generate_simple_tcp_header<'p>(packet: &'p mut [u8]) {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[..]).unwrap();
        tcp_header.set_source(57359);
        assert_eq!(tcp_header.get_source(), 57359);

        tcp_header.set_destination(9666);
        assert_eq!(tcp_header.get_destination(), 9666);

        tcp_header.set_sequence(3741771494);
        assert_eq!(tcp_header.get_sequence(), 3741771494);

        tcp_header.set_acknowledgement(3375208561);
        assert_eq!(tcp_header.get_acknowledgement(), 3375208561);

        tcp_header.set_data_offset_and_reserved(0x80);
        assert_eq!(tcp_header.get_data_offset_and_reserved(), 0x80);

        tcp_header.set_control_bits(0x18);
        assert_eq!(tcp_header.get_control_bits(), 0x18);

        tcp_header.set_window(0x02ab);
        assert_eq!(tcp_header.get_window(), 0x02ab);

        tcp_header.set_checksum(0xfe2d);
        assert_eq!(tcp_header.get_checksum(), 0xfe2d);

        tcp_header.set_urgent_pointer(0x0000);
        assert_eq!(tcp_header.get_urgent_pointer(), 0x0000);

        let mut options: Vec<TcpOptions> = vec![];
        let tcp_option = TcpOptions{
            kind: 0x1,
            data: vec![0x01,0x08,0x0a,0x1d,0xfc,0xcb,0x76,0x1d,0xfc,0xbe,0x62],
        };
        options.push(tcp_option);
        tcp_header.set_options(options);
    }
}
<|endoftext|>


<commit_before>pub mod home {
    use chrono::{NaiveDate};

    struct NewsItem {
        pub title: String,
        pub date: NaiveDate,
    }

    fn changeFuncName() -> [NewsItem; 1] {
        let aNewsItems: [NewsItem; 1] = [
            NewsItem{
                title: String::from(
                    "Ethereum bounty contractshave now been added for anyone that would like to try to push the boundaries of human knowledge. The first contract is a competition for the correct solution to a³+b³+c³ = 33. Tweet me if you need assistance using these contracts!"),
                date: NaiveDate::from_ymd(2019, 1, 22)
            }
        ];
        aNewsItems
    }

}<commit_msg>snake case news_items<commit_after>pub mod home {
    use chrono::{NaiveDate};

    struct NewsItem {
        pub title: String,
        pub date: NaiveDate,
    }

    fn changeFuncName() -> [NewsItem; 1] {
        let news_items: [NewsItem; 1] = [
            NewsItem{
                title: String::from(
                    "Ethereum bounty contractshave now been added for anyone that would like to try to push the boundaries of human knowledge. The first contract is a competition for the correct solution to a³+b³+c³ = 33. Tweet me if you need assistance using these contracts!"),
                date: NaiveDate::from_ymd(2019, 1, 22)
            }
        ];
        news_items
    }

}<|endoftext|>