<commit_before>use std::io::{self, Stdout, stdout, stdin, Write};
use termion::input::TermRead;
use termion::raw::{IntoRawMode, RawTerminal};

use super::*;
use keymap;

/// The default for `Context.word_fn`.
pub fn get_buffer_words(buf: &Buffer) -> Vec<(usize, usize)> {
    let mut res = Vec::new();

    let mut word_start = None;
    let mut just_had_backslash = false;

    for (i, &c) in buf.chars().enumerate() {
        if c == '\\' {
            just_had_backslash = true;
            continue;
        }

        if let Some(start) = word_start {
            if c == ' ' && !just_had_backslash {
                res.push((start, i));
                word_start = None;
            }
        } else {
            if c != ' ' {
                word_start = Some(i);
            }
        }

        just_had_backslash = false;
    }

    if let Some(start) = word_start {
        res.push((start, buf.num_chars()));
    }

    res
}

/// The key bindings to use.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyBindings {
    Vi,
    Emacs,
}

pub struct Context {
    pub history: History,
    pub completer: Option<Box<Completer>>,
    pub word_fn: Box<Fn(&Buffer) -> Vec<(usize, usize)>>,
    pub key_bindings: KeyBindings,
}

impl Context {
    pub fn new() -> Self {
        Context {
            history: History::new(),
            completer: None,
            word_fn: Box::new(get_buffer_words),
            key_bindings: KeyBindings::Emacs,
        }
    }

    /// Creates an `Editor` and feeds it keypresses from stdin until the line is entered.
    /// The output is stdout.
    /// The returned line has the newline removed.
    /// Before returning, will revert all changes to the history buffers.
    pub fn read_line<P: Into<String>>(&mut self,
                                      prompt: P,
                                      mut handler: &mut EventHandler<RawTerminal<Stdout>>)
                                      -> io::Result<String> {
        let res = {
            let stdout = stdout().into_raw_mode().unwrap();
            let ed = try!(Editor::new(stdout, prompt.into(), self));
            Self::handle_keys(keymap::Emacs::new(ed), handler)
        };

        self.revert_all_history();
        res
    }

    fn handle_keys<'a, T, W: Write, M: KeyMap<'a, W, T>>(mut keymap: M,
                                                         mut handler: &mut EventHandler<W>)
                                                         -> io::Result<String>
        where String: From<M>
    {
        let stdin = stdin();
        for c in stdin.keys() {
            if try!(keymap.handle_key(c.unwrap(), handler)) {
                break;
            }
        }

        Ok(keymap.into())
    }

    pub fn revert_all_history(&mut self) {
        for buf in &mut self.history.buffers {
            buf.revert();
        }
    }
}
<commit_msg>use vi and emacs KeyMaps in Context<commit_after>use std::io::{self, Stdout, stdout, stdin, Write};
use termion::input::TermRead;
use termion::raw::{IntoRawMode, RawTerminal};

use super::*;
use keymap;

/// The default for `Context.word_fn`.
pub fn get_buffer_words(buf: &Buffer) -> Vec<(usize, usize)> {
    let mut res = Vec::new();

    let mut word_start = None;
    let mut just_had_backslash = false;

    for (i, &c) in buf.chars().enumerate() {
        if c == '\\' {
            just_had_backslash = true;
            continue;
        }

        if let Some(start) = word_start {
            if c == ' ' && !just_had_backslash {
                res.push((start, i));
                word_start = None;
            }
        } else {
            if c != ' ' {
                word_start = Some(i);
            }
        }

        just_had_backslash = false;
    }

    if let Some(start) = word_start {
        res.push((start, buf.num_chars()));
    }

    res
}

/// The key bindings to use.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyBindings {
    Vi,
    Emacs,
}

pub struct Context {
    pub history: History,
    pub completer: Option<Box<Completer>>,
    pub word_fn: Box<Fn(&Buffer) -> Vec<(usize, usize)>>,
    pub key_bindings: KeyBindings,
}

impl Context {
    pub fn new() -> Self {
        Context {
            history: History::new(),
            completer: None,
            word_fn: Box::new(get_buffer_words),
            key_bindings: KeyBindings::Emacs,
        }
    }

    /// Creates an `Editor` and feeds it keypresses from stdin until the line is entered.
    /// The output is stdout.
    /// The returned line has the newline removed.
    /// Before returning, will revert all changes to the history buffers.
    pub fn read_line<P: Into<String>>(&mut self,
                                      prompt: P,
                                      mut handler: &mut EventHandler<RawTerminal<Stdout>>)
                                      -> io::Result<String> {
        let res = {
            let stdout = stdout().into_raw_mode().unwrap();
            let ed = try!(Editor::new(stdout, prompt.into(), self));
            match self.key_bindings {
                KeyBindings::Emacs => Self::handle_keys(keymap::Emacs::new(ed), handler),
                KeyBindings::Vi => Self::handle_keys(keymap::Vi::new(ed), handler),
            }
        };

        self.revert_all_history();
        res
    }

    fn handle_keys<'a, T, W: Write, M: KeyMap<'a, W, T>>(mut keymap: M,
                                                         mut handler: &mut EventHandler<W>)
                                                         -> io::Result<String>
        where String: From<M>
    {
        let stdin = stdin();
        for c in stdin.keys() {
            if try!(keymap.handle_key(c.unwrap(), handler)) {
                break;
            }
        }

        Ok(keymap.into())
    }

    pub fn revert_all_history(&mut self) {
        for buf in &mut self.history.buffers {
            buf.revert();
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use std::collections::hashmap::HashMap;

#[cfg(test)]
mod tests;

pub struct IrcMessage {
    pub tags: HashMap<String, String>,
    pub prefix: Option<String>,
    pub command: Option<String>,
    pub params: Vec<String>
}

impl IrcMessage {
    pub fn new_empty() -> IrcMessage {
        IrcMessage {
            tags: HashMap::new(),
            prefix: None,
            command: None,
            params: Vec::new()
        }
    }
}

fn find_after_n(string: &str, c: char, n: uint) -> Option<uint> {
    string.slice_from(n).find(c).map(|a| a + n)
}

fn is_white(c: &char) -> bool { *c == ' ' }
fn not_white(c: &char) -> bool { !is_white(c) }

pub fn parse(line: &str) -> Result<IrcMessage, ()> {
    let mut message = IrcMessage::new_empty();
    let mut chars = line.chars().peekable();
    // Tags
    if chars.peek() == Some(&'@') {
        let mut tags = chars.by_ref().skip(1).take_while(not_white);
        loop {
            let mut tag = tags.by_ref().take_while(|&c| c != ';').peekable();
            if tag.peek() == None { break; }
            let name = tag.by_ref().take_while(|&c| c != '=').collect();
            let mut rest = tag.peekable();
            let value = if rest.is_empty() {
                "true".to_string()
            } else {
                rest.collect()
            };
            message.tags.insert(name, value);
        }
    }
    let mut chars = chars.peekable();
    if chars.is_empty() { return Err(()); }
    let mut chars = chars.skip_while(is_white).peekable();

    // Prefix
    if chars.peek() == Some(&':') {
        let prefix = chars.by_ref().skip(1).take_while(not_white).collect();
        message.prefix = Some(prefix);
    }

    let mut chars = chars.peekable();
    if chars.is_empty() { return Err(()) }
    let mut chars = chars.skip_while(is_white);

    // Command
    let command = chars.by_ref().take_while(not_white).collect();
    message.command = Some(command);

    let mut chars = chars.skip_while(is_white);

    // Params
    loop {
        let mut chars = chars.by_ref().skip_while(is_white).peekable();
        match chars.peek() {
            None => {
                println!("breaking on none");
                break; }
            Some(&':') => {
                message.params.push(chars.skip(1).collect());
                println!("breaking on done");
                break;
            }
            _ => {
                println!("\nbefore");
                chars.by_ref().inspect(|&c| print!("{}", c) );
                message.params.push(chars.by_ref().take_while(not_white).collect());
            }
        }
    }

    Ok(message)
}
<commit_msg>restart types by collecting and then iterating again<commit_after>#![allow(dead_code)]
use std::collections::hashmap::HashMap;
use std::vec::MoveItems;

#[cfg(test)]
mod tests;

pub struct IrcMessage {
    pub tags: HashMap<String, String>,
    pub prefix: Option<String>,
    pub command: Option<String>,
    pub params: Vec<String>
}

impl IrcMessage {
    pub fn new_empty() -> IrcMessage {
        IrcMessage {
            tags: HashMap::new(),
            prefix: None,
            command: None,
            params: Vec::new()
        }
    }
}

fn find_after_n(string: &str, c: char, n: uint) -> Option<uint> {
    string.slice_from(n).find(c).map(|a| a + n)
}

fn is_white(c: &char) -> bool { *c == ' ' }
fn not_white(c: &char) -> bool { !is_white(c) }

fn strip<I: Iterator<char>>(iter: I) -> MoveItems<char> {
    let vec: Vec<char> = iter.skip_while(is_white).collect();
    vec.move_iter()
}

pub fn parse(line: &str) -> Result<IrcMessage, ()> {
    let mut message = IrcMessage::new_empty();
    let mut chars = line.chars().peekable();
    // Tags
    if chars.peek() == Some(&'@') {
        let mut tags = chars.by_ref().skip(1).take_while(not_white);
        loop {
            let mut tag = tags.by_ref().take_while(|&c| c != ';').peekable();
            if tag.peek() == None { break; }
            let name = tag.by_ref().take_while(|&c| c != '=').collect();
            let mut rest = tag.peekable();
            let value = if rest.is_empty() {
                "true".to_string()
            } else {
                rest.collect()
            };
            message.tags.insert(name, value);
        }
    }
    let mut chars = chars.peekable();
    if chars.is_empty() { return Err(()); }
    let mut chars = strip(chars).peekable();

    // Prefix
    if chars.peek() == Some(&':') {
        let prefix = chars.by_ref().skip(1).take_while(not_white).collect();
        message.prefix = Some(prefix);
    }

    let mut chars = chars.peekable();
    if chars.is_empty() { return Err(()) }
    let mut chars = strip(chars);

    // Command
    let command = chars.by_ref().take_while(not_white).collect();
    message.command = Some(command);
    let mut chars = strip(chars);

    // Params
    loop {
        let mut chars = chars.by_ref().skip_while(is_white).peekable();
        match chars.peek() {
            None => {
                println!("breaking on none");
                break; }
            Some(&':') => {
                message.params.push(chars.skip(1).collect());
                println!("breaking on done");
                break;
            }
            _ => {
                println!("\nbefore");
                chars.by_ref().inspect(|&c| print!("{}", c) );
                message.params.push(chars.by_ref().take_while(not_white).collect());
            }
        }
    }

    Ok(message)
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

#[macro_use]
extern crate pest;

extern crate rand;

mod parse;

use pest::*;
use parse::*;

#[derive(Debug)]
pub struct Roller<'a> {
    roll: &'a str,
    total: i32,
}

impl<'a> Roller<'a> {
     fn new(roll: &str) -> Roller {
         let mut parser = Rdp::new(StringInput::new(roll));
         parser.expression();

         Roller{
             roll: roll,
             total: parser.compute()
         }
     }

     fn reroll(&mut self) {
         let mut parser = Rdp::new(StringInput::new(self.roll));
         parser.expression();

         self.total = parser.compute();
     }

     fn total(&self) -> i32 {
         self.total
     }
}

#[test]
fn it_works() {
    let mut roller = Roller::new("4d6");
    let orig = roller.total();

    assert!((4 <= roller.total()) && (roller.total() <= 24));

    roller.reroll();

    assert!(orig != roller.total());
}<commit_msg>reroll() method returns value<commit_after>#![allow(dead_code)]

#[macro_use]
extern crate pest;

extern crate rand;

mod parse;

use pest::*;
use parse::*;

#[derive(Debug)]
pub struct Roller<'a> {
    roll: &'a str,
    total: i32,
}

impl<'a> Roller<'a> {
     fn new(roll: &str) -> Roller {
         let mut parser = Rdp::new(StringInput::new(roll));
         parser.expression();

         Roller{
             roll: roll,
             total: parser.compute()
         }
     }

     fn reroll(&mut self) -> i32 {
         let mut parser = Rdp::new(StringInput::new(self.roll));
         parser.expression();

         self.total = parser.compute();

         self.total
     }

     fn total(&self) -> i32 {
         self.total
     }
}

#[test]
fn it_works() {
    let mut roller = Roller::new("4d6");

    assert!((4 <= roller.total()) && (roller.total() <= 24));

    assert!(roller.total() != roller.reroll());
}<|endoftext|>


<commit_before>use types::{OscPacket, OscType, OscResult, OscMessage, OscBundle};
use errors::OscError;
use utils;

use std::io;
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> OscResult<OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(OscError::BadBundle);
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::new();
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle);
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    match cursor.read_until(0, &mut str_buf) {
        Ok(_) => {
            pad_cursor(cursor);
            String::from_utf8(str_buf)
                .map_err(|e| OscError::StringError(e))
                .map(|s| s.trim_matches(0u8 as char).to_string())
        }
        Err(e) => Err(OscError::ReadError(e)),
    }
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> OscResult<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        match read_osc_arg(cursor, tag) {
            Ok(arg) => {
                args.push(arg);
            }
            Err(e) => return Err(e),
        }
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> OscResult<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(|f| OscType::Float(f))
                  .map_err(|e| OscError::ByteOrderError(e))
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(|d| OscType::Double(d))
                  .map_err(|e| OscError::ByteOrderError(e))
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(|i| OscType::Int(i))
                  .map_err(|e| OscError::ByteOrderError(e))
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(|l| OscType::Long(l))
                  .map_err(|e| OscError::ByteOrderError(e))
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            // http://opensoundcontrol.org/node/3/#timetags
            read_time_tag(cursor)
        }
        'b' => {
            match cursor.read_u32::<BigEndian>() {
                Ok(size) => {
                    let mut buf: Vec<u8> = Vec::with_capacity(size as usize);
                    match cursor.take(size as u64).read(&mut buf) {
                        Ok(blob_size) => Ok(OscType::Blob(buf)),
                        Err(e) => Err(OscError::ReadError(e)),
                    }
                }
                // TODO: use correct error type
                Err(e) => return Err(OscError::BadBundle),
            }
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    match cursor.read_u32::<BigEndian>() {
        Ok(date) => {
            match cursor.read_u32::<BigEndian>() {
                Ok(frac) => Ok(OscType::Time(date, frac)),
                Err(e) => Err(OscError::ByteOrderError(e)),
            }
        }
        Err(e) => Err(OscError::ByteOrderError(e)),
    }
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<commit_msg>Refactor `read_osc_string`<commit_after>use types::{OscPacket, OscType, OscResult, OscMessage, OscBundle};
use errors::OscError;
use utils;

use std::io;
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> OscResult<OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(OscError::BadBundle);
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::new();
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle);
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> OscResult<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        match read_osc_arg(cursor, tag) {
            Ok(arg) => {
                args.push(arg);
            }
            Err(e) => return Err(e),
        }
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> OscResult<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(|f| OscType::Float(f))
                  .map_err(|e| OscError::ByteOrderError(e))
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(|d| OscType::Double(d))
                  .map_err(|e| OscError::ByteOrderError(e))
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(|i| OscType::Int(i))
                  .map_err(|e| OscError::ByteOrderError(e))
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(|l| OscType::Long(l))
                  .map_err(|e| OscError::ByteOrderError(e))
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            // http://opensoundcontrol.org/node/3/#timetags
            read_time_tag(cursor)
        }
        'b' => {
            match cursor.read_u32::<BigEndian>() {
                Ok(size) => {
                    let mut buf: Vec<u8> = Vec::with_capacity(size as usize);
                    match cursor.take(size as u64).read(&mut buf) {
                        Ok(blob_size) => Ok(OscType::Blob(buf)),
                        Err(e) => Err(OscError::ReadError(e)),
                    }
                }
                // TODO: use correct error type
                Err(e) => return Err(OscError::BadBundle),
            }
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    match cursor.read_u32::<BigEndian>() {
        Ok(date) => {
            match cursor.read_u32::<BigEndian>() {
                Ok(frac) => Ok(OscType::Time(date, frac)),
                Err(e) => Err(OscError::ByteOrderError(e)),
            }
        }
        Err(e) => Err(OscError::ByteOrderError(e)),
    }
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<|endoftext|>


<commit_before>use crate::{dns_probe_udp, DnsUDPParser};
use nom::be_u16;
use rparser::{RBuilder, RParser, R_STATUS_FAIL};

pub struct DnsTCPBuilder {}
impl RBuilder for DnsTCPBuilder {
    fn new(&self) -> Box<RParser> {
        Box::new(DnsTCPParser::new(b"DNS/TCP"))
    }
    fn probe(&self, i: &[u8]) -> bool {
        dns_probe_tcp(i)
    }
}

pub struct DnsTCPParser<'a> {
    _name: Option<&'a [u8]>,
    parser: DnsUDPParser<'a>,
}

impl<'a> DnsTCPParser<'a> {
    pub fn new(name: &'a [u8]) -> DnsTCPParser<'a> {
        DnsTCPParser {
            _name: Some(name),
            parser: DnsUDPParser::new(name),
        }
    }
}

impl<'a> RParser for DnsTCPParser<'a> {
    fn parse(&mut self, buf: &[u8], direction: u8) -> u32 {
        match be_u16(buf) {
            Ok((rem,l)) => {
                if l > rem.len() as u16 {
                    return R_STATUS_FAIL;
                }
                self.parser.parse(rem, direction)
            }
            _ => R_STATUS_FAIL
        }
    }
}

pub fn dns_probe_tcp(i: &[u8]) -> bool {
    if i.len() <= 14 {
        return false;
    }
    match be_u16(i) {
        Ok((rem, record_len)) => {
            if record_len > rem.len() as u16 {
                return false;
            }
            return dns_probe_udp(rem);
        }
        _ => {
            return false;
        }
    }
}
<commit_msg>dns: try to limit false positives, reject messages longer than a DNS msg<commit_after>use crate::{dns_probe_udp, DnsUDPParser};
use nom::be_u16;
use rparser::{RBuilder, RParser, R_STATUS_FAIL};

pub struct DnsTCPBuilder {}
impl RBuilder for DnsTCPBuilder {
    fn new(&self) -> Box<RParser> {
        Box::new(DnsTCPParser::new(b"DNS/TCP"))
    }
    fn probe(&self, i: &[u8]) -> bool {
        dns_probe_tcp(i)
    }
}

pub struct DnsTCPParser<'a> {
    _name: Option<&'a [u8]>,
    parser: DnsUDPParser<'a>,
}

impl<'a> DnsTCPParser<'a> {
    pub fn new(name: &'a [u8]) -> DnsTCPParser<'a> {
        DnsTCPParser {
            _name: Some(name),
            parser: DnsUDPParser::new(name),
        }
    }
}

impl<'a> RParser for DnsTCPParser<'a> {
    fn parse(&mut self, buf: &[u8], direction: u8) -> u32 {
        match be_u16(buf) {
            Ok((rem,l)) => {
                if l > rem.len() as u16 {
                    return R_STATUS_FAIL;
                }
                self.parser.parse(rem, direction)
            }
            _ => R_STATUS_FAIL
        }
    }
}

pub fn dns_probe_tcp(i: &[u8]) -> bool {
    if i.len() <= 14 {
        return false;
    }
    match be_u16(i) {
        Ok((rem, record_len)) => {
            if record_len < i.len() as u16 {
                return false;
            }
            if record_len > rem.len() as u16 {
                return false;
            }
            return dns_probe_udp(rem);
        }
        _ => {
            return false;
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![feature(rustc_private)]
#![feature(custom_attribute)]
#![feature(slice_splits)]
#![feature(catch_panic)]
#![allow(unused_attributes)]

// TODO we're going to allocate a whole bunch of temp Strings, is it worth
// keeping some scratch mem for this and running our own StrPool?
// TODO for lint violations of names, emit a refactor script

#[macro_use]
extern crate log;

extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate syntax;
extern crate rustc_serialize;

extern crate strings;

extern crate unicode_segmentation;
extern crate regex;
extern crate diff;
extern crate term;

use rustc::session::Session;
use rustc::session::config as rustc_config;
use rustc::session::config::Input;
use rustc_driver::{driver, CompilerCalls, Compilation};

use syntax::ast;
use syntax::codemap::CodeMap;
use syntax::diagnostics;

use std::path::PathBuf;
use std::collections::HashMap;
use std::fmt;
use std::mem::swap;
use std::str::FromStr;

use issues::{BadIssueSeeker, Issue};
use filemap::FileMap;
use visitor::FmtVisitor;
use config::Config;

#[macro_use]
mod utils;
pub mod config;
mod filemap;
mod visitor;
mod items;
mod missed_spans;
mod lists;
mod types;
mod expr;
mod imports;
mod issues;
mod rewrite;
mod string;
mod comment;
mod modules;
pub mod rustfmt_diff;
mod chains;
mod macros;

const MIN_STRING: usize = 10;
// When we get scoped annotations, we should have rustfmt::skip.
const SKIP_ANNOTATION: &'static str = "rustfmt_skip";

#[derive(Copy, Clone)]
pub enum WriteMode {
    // Backups the original file and overwrites the orignal.
    Replace,
    // Overwrites original file without backup.
    Overwrite,
    // str is the extension of the new file.
    NewFile(&'static str),
    // Write the output to stdout.
    Display,
    // Write the diff to stdout.
    Diff,
    // Return the result as a mapping from filenames to Strings.
    Return(&'static Fn(HashMap<String, String>)),
}

impl FromStr for WriteMode {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "replace" => Ok(WriteMode::Replace),
            "display" => Ok(WriteMode::Display),
            "overwrite" => Ok(WriteMode::Overwrite),
            "diff" => Ok(WriteMode::Diff),
            _ => Err(()),
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum NewlineStyle {
    Windows, // \r\n
    Unix, // \n
}

impl_enum_decodable!(NewlineStyle, Windows, Unix);

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum BraceStyle {
    AlwaysNextLine,
    PreferSameLine,
    // Prefer same line except where there is a where clause, in which case force
    // the brace to the next line.
    SameLineWhere,
}

impl_enum_decodable!(BraceStyle, AlwaysNextLine, PreferSameLine, SameLineWhere);

// How to indent a function's return type.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum ReturnIndent {
    // Aligned with the arguments
    WithArgs,
    // Aligned with the where clause
    WithWhereClause,
}

impl_enum_decodable!(ReturnIndent, WithArgs, WithWhereClause);

// How to stle a struct literal.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum StructLitStyle {
    // First line on the same line as the opening brace, all lines aligned with
    // the first line.
    Visual,
    // First line is on a new line and all lines align with block indent.
    Block,
    // FIXME Maybe we should also have an option to align types.
}

impl_enum_decodable!(StructLitStyle, Visual, Block);

enum ErrorKind {
    // Line has exceeded character limit
    LineOverflow,
    // Line ends in whitespace
    TrailingWhitespace,
    // TO-DO or FIX-ME item without an issue number
    BadIssue(Issue),
}

impl fmt::Display for ErrorKind {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            ErrorKind::LineOverflow => {
                write!(fmt, "line exceeded maximum length")
            }
            ErrorKind::TrailingWhitespace => {
                write!(fmt, "left behind trailing whitespace")
            }
            ErrorKind::BadIssue(issue) => {
                write!(fmt, "found {}", issue)
            }
        }
    }
}

// Formatting errors that are identified *after* rustfmt has run
struct FormattingError {
    line: u32,
    kind: ErrorKind,
}

impl FormattingError {
    fn msg_prefix(&self) -> &str {
        match self.kind {
            ErrorKind::LineOverflow |
            ErrorKind::TrailingWhitespace => "Rustfmt failed at",
            ErrorKind::BadIssue(_) => "WARNING:",
        }
    }

    fn msg_suffix(&self) -> &str {
        match self.kind {
            ErrorKind::LineOverflow |
            ErrorKind::TrailingWhitespace => "(sorry)",
            ErrorKind::BadIssue(_) => "",
        }
    }
}

struct FormatReport {
    // Maps stringified file paths to their associated formatting errors
    file_error_map: HashMap<String, Vec<FormattingError>>,
}

impl fmt::Display for FormatReport {
    // Prints all the formatting errors.
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        for (file, errors) in &self.file_error_map {
            for error in errors {
                try!(write!(fmt,
                            "{} {}:{}: {} {}\n",
                            error.msg_prefix(),
                            file,
                            error.line,
                            error.kind,
                            error.msg_suffix()));
            }
        }
        Ok(())
    }
}

// Formatting which depends on the AST.
fn fmt_ast(krate: &ast::Crate, codemap: &CodeMap, config: &Config) -> FileMap {
    let mut file_map = FileMap::new();
    for (path, module) in modules::list_files(krate, codemap) {
        let path = path.to_str().unwrap();
        let mut visitor = FmtVisitor::from_codemap(codemap, config);
        visitor.format_separate_mod(module, path);
        file_map.insert(path.to_owned(), visitor.buffer);
    }
    file_map
}

// Formatting done on a char by char or line by line basis.
// TODO warn on bad license
// TODO other stuff for parity with make tidy
fn fmt_lines(file_map: &mut FileMap, config: &Config) -> FormatReport {
    let mut truncate_todo = Vec::new();
    let mut report = FormatReport { file_error_map: HashMap::new() };

    // Iterate over the chars in the file map.
    for (f, text) in file_map.iter() {
        let mut trims = vec![];
        let mut last_wspace: Option<usize> = None;
        let mut line_len = 0;
        let mut cur_line = 1;
        let mut newline_count = 0;
        let mut errors = vec![];
        let mut issue_seeker = BadIssueSeeker::new(config.report_todo, config.report_fixme);

        for (c, b) in text.chars() {
            if c == '\r' {
                continue;
            }

            // Add warnings for bad todos/ fixmes
            if let Some(issue) = issue_seeker.inspect(c) {
                errors.push(FormattingError { line: cur_line, kind: ErrorKind::BadIssue(issue) });
            }

            if c == '\n' {
                // Check for (and record) trailing whitespace.
                if let Some(lw) = last_wspace {
                    trims.push((cur_line, lw, b));
                    line_len -= b - lw;
                }
                // Check for any line width errors we couldn't correct.
                if line_len > config.max_width {
                    errors.push(FormattingError { line: cur_line, kind: ErrorKind::LineOverflow });
                }
                line_len = 0;
                cur_line += 1;
                newline_count += 1;
                last_wspace = None;
            } else {
                newline_count = 0;
                line_len += 1;
                if c.is_whitespace() {
                    if last_wspace.is_none() {
                        last_wspace = Some(b);
                    }
                } else {
                    last_wspace = None;
                }
            }
        }

        if newline_count > 1 {
            debug!("track truncate: {} {} {}", f, text.len, newline_count);
            truncate_todo.push((f.to_owned(), text.len - newline_count + 1))
        }

        for &(l, _, _) in &trims {
            errors.push(FormattingError { line: l, kind: ErrorKind::TrailingWhitespace });
        }

        report.file_error_map.insert(f.to_owned(), errors);
    }

    for (f, l) in truncate_todo {
        file_map.get_mut(&f).unwrap().truncate(l);
    }

    report
}

struct RustFmtCalls {
    write_mode: WriteMode,
    config: Option<Box<config::Config>>,
}

impl<'a> CompilerCalls<'a> for RustFmtCalls {
    fn no_input(&mut self,
                _: &getopts::Matches,
                _: &rustc_config::Options,
                _: &Option<PathBuf>,
                _: &Option<PathBuf>,
                _: &diagnostics::registry::Registry)
                -> Option<(Input, Option<PathBuf>)> {
        panic!("No input supplied to RustFmt");
    }

    fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> {
        let write_mode = self.write_mode;

        let mut config_option = None;
        swap(&mut self.config, &mut config_option);
        let config = config_option.unwrap();

        let mut control = driver::CompileController::basic();
        control.after_parse.stop = Compilation::Stop;
        control.after_parse.callback = Box::new(move |state| {
            let krate = state.krate.unwrap();
            let codemap = state.session.codemap();
            let mut file_map = fmt_ast(krate, codemap, &*config);
            // For some reason, the codemap does not include terminating
            // newlines so we must add one on for each file. This is sad.
            filemap::append_newlines(&mut file_map);
            println!("{}", fmt_lines(&mut file_map, &*config));

            let result = filemap::write_all_files(&file_map, write_mode, &*config);

            match result {
                Err(msg) => println!("Error writing files: {}", msg),
                Ok(result) => {
                    if let WriteMode::Return(callback) = write_mode {
                        callback(result);
                    }
                }
            }
        });

        control
    }
}

// args are the arguments passed on the command line, generally passed through
// to the compiler.
// write_mode determines what happens to the result of running rustfmt, see
// WriteMode.
pub fn run(args: Vec<String>, write_mode: WriteMode, config: Box<Config>) {
    let mut call_ctxt = RustFmtCalls { write_mode: write_mode, config: Some(config) };
    rustc_driver::run_compiler(&args, &mut call_ctxt);
}
<commit_msg>Split formatting function from side effects<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![feature(rustc_private)]
#![feature(custom_attribute)]
#![feature(slice_splits)]
#![feature(catch_panic)]
#![allow(unused_attributes)]

// TODO we're going to allocate a whole bunch of temp Strings, is it worth
// keeping some scratch mem for this and running our own StrPool?
// TODO for lint violations of names, emit a refactor script

#[macro_use]
extern crate log;

extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate syntax;
extern crate rustc_serialize;

extern crate strings;

extern crate unicode_segmentation;
extern crate regex;
extern crate diff;
extern crate term;

use rustc::session::Session;
use rustc::session::config as rustc_config;
use rustc::session::config::Input;
use rustc_driver::{driver, CompilerCalls, Compilation};

use syntax::ast;
use syntax::codemap::CodeMap;
use syntax::diagnostics;

use std::path::PathBuf;
use std::collections::HashMap;
use std::fmt;
use std::mem::swap;
use std::str::FromStr;
use std::rc::Rc;
use std::cell::RefCell;

use issues::{BadIssueSeeker, Issue};
use filemap::FileMap;
use visitor::FmtVisitor;
use config::Config;

#[macro_use]
mod utils;
pub mod config;
mod filemap;
mod visitor;
mod items;
mod missed_spans;
mod lists;
mod types;
mod expr;
mod imports;
mod issues;
mod rewrite;
mod string;
mod comment;
mod modules;
pub mod rustfmt_diff;
mod chains;
mod macros;

const MIN_STRING: usize = 10;
// When we get scoped annotations, we should have rustfmt::skip.
const SKIP_ANNOTATION: &'static str = "rustfmt_skip";

#[derive(Copy, Clone)]
pub enum WriteMode {
    // Backups the original file and overwrites the orignal.
    Replace,
    // Overwrites original file without backup.
    Overwrite,
    // str is the extension of the new file.
    NewFile(&'static str),
    // Write the output to stdout.
    Display,
    // Write the diff to stdout.
    Diff,
    // Return the result as a mapping from filenames to Strings.
    Return(&'static Fn(HashMap<String, String>)),
}

impl FromStr for WriteMode {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "replace" => Ok(WriteMode::Replace),
            "display" => Ok(WriteMode::Display),
            "overwrite" => Ok(WriteMode::Overwrite),
            "diff" => Ok(WriteMode::Diff),
            _ => Err(()),
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum NewlineStyle {
    Windows, // \r\n
    Unix, // \n
}

impl_enum_decodable!(NewlineStyle, Windows, Unix);

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum BraceStyle {
    AlwaysNextLine,
    PreferSameLine,
    // Prefer same line except where there is a where clause, in which case force
    // the brace to the next line.
    SameLineWhere,
}

impl_enum_decodable!(BraceStyle, AlwaysNextLine, PreferSameLine, SameLineWhere);

// How to indent a function's return type.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum ReturnIndent {
    // Aligned with the arguments
    WithArgs,
    // Aligned with the where clause
    WithWhereClause,
}

impl_enum_decodable!(ReturnIndent, WithArgs, WithWhereClause);

// How to stle a struct literal.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum StructLitStyle {
    // First line on the same line as the opening brace, all lines aligned with
    // the first line.
    Visual,
    // First line is on a new line and all lines align with block indent.
    Block,
    // FIXME Maybe we should also have an option to align types.
}

impl_enum_decodable!(StructLitStyle, Visual, Block);

enum ErrorKind {
    // Line has exceeded character limit
    LineOverflow,
    // Line ends in whitespace
    TrailingWhitespace,
    // TO-DO or FIX-ME item without an issue number
    BadIssue(Issue),
}

impl fmt::Display for ErrorKind {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            ErrorKind::LineOverflow => {
                write!(fmt, "line exceeded maximum length")
            }
            ErrorKind::TrailingWhitespace => {
                write!(fmt, "left behind trailing whitespace")
            }
            ErrorKind::BadIssue(issue) => {
                write!(fmt, "found {}", issue)
            }
        }
    }
}

// Formatting errors that are identified *after* rustfmt has run
struct FormattingError {
    line: u32,
    kind: ErrorKind,
}

impl FormattingError {
    fn msg_prefix(&self) -> &str {
        match self.kind {
            ErrorKind::LineOverflow |
            ErrorKind::TrailingWhitespace => "Rustfmt failed at",
            ErrorKind::BadIssue(_) => "WARNING:",
        }
    }

    fn msg_suffix(&self) -> &str {
        match self.kind {
            ErrorKind::LineOverflow |
            ErrorKind::TrailingWhitespace => "(sorry)",
            ErrorKind::BadIssue(_) => "",
        }
    }
}

struct FormatReport {
    // Maps stringified file paths to their associated formatting errors
    file_error_map: HashMap<String, Vec<FormattingError>>,
}

impl fmt::Display for FormatReport {
    // Prints all the formatting errors.
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        for (file, errors) in &self.file_error_map {
            for error in errors {
                try!(write!(fmt,
                            "{} {}:{}: {} {}\n",
                            error.msg_prefix(),
                            file,
                            error.line,
                            error.kind,
                            error.msg_suffix()));
            }
        }
        Ok(())
    }
}

// Formatting which depends on the AST.
fn fmt_ast(krate: &ast::Crate, codemap: &CodeMap, config: &Config) -> FileMap {
    let mut file_map = FileMap::new();
    for (path, module) in modules::list_files(krate, codemap) {
        let path = path.to_str().unwrap();
        let mut visitor = FmtVisitor::from_codemap(codemap, config);
        visitor.format_separate_mod(module, path);
        file_map.insert(path.to_owned(), visitor.buffer);
    }
    file_map
}

// Formatting done on a char by char or line by line basis.
// TODO warn on bad license
// TODO other stuff for parity with make tidy
fn fmt_lines(file_map: &mut FileMap, config: &Config) -> FormatReport {
    let mut truncate_todo = Vec::new();
    let mut report = FormatReport { file_error_map: HashMap::new() };

    // Iterate over the chars in the file map.
    for (f, text) in file_map.iter() {
        let mut trims = vec![];
        let mut last_wspace: Option<usize> = None;
        let mut line_len = 0;
        let mut cur_line = 1;
        let mut newline_count = 0;
        let mut errors = vec![];
        let mut issue_seeker = BadIssueSeeker::new(config.report_todo, config.report_fixme);

        for (c, b) in text.chars() {
            if c == '\r' {
                continue;
            }

            // Add warnings for bad todos/ fixmes
            if let Some(issue) = issue_seeker.inspect(c) {
                errors.push(FormattingError { line: cur_line, kind: ErrorKind::BadIssue(issue) });
            }

            if c == '\n' {
                // Check for (and record) trailing whitespace.
                if let Some(lw) = last_wspace {
                    trims.push((cur_line, lw, b));
                    line_len -= b - lw;
                }
                // Check for any line width errors we couldn't correct.
                if line_len > config.max_width {
                    errors.push(FormattingError { line: cur_line, kind: ErrorKind::LineOverflow });
                }
                line_len = 0;
                cur_line += 1;
                newline_count += 1;
                last_wspace = None;
            } else {
                newline_count = 0;
                line_len += 1;
                if c.is_whitespace() {
                    if last_wspace.is_none() {
                        last_wspace = Some(b);
                    }
                } else {
                    last_wspace = None;
                }
            }
        }

        if newline_count > 1 {
            debug!("track truncate: {} {} {}", f, text.len, newline_count);
            truncate_todo.push((f.to_owned(), text.len - newline_count + 1))
        }

        for &(l, _, _) in &trims {
            errors.push(FormattingError { line: l, kind: ErrorKind::TrailingWhitespace });
        }

        report.file_error_map.insert(f.to_owned(), errors);
    }

    for (f, l) in truncate_todo {
        file_map.get_mut(&f).unwrap().truncate(l);
    }

    report
}

struct RustFmtCalls {
    config: Option<Box<config::Config>>,
    // FIXME: there's likely a better type for the job.
    result: Rc<RefCell<Option<FileMap>>>,
}

impl<'a> CompilerCalls<'a> for RustFmtCalls {
    fn no_input(&mut self,
                _: &getopts::Matches,
                _: &rustc_config::Options,
                _: &Option<PathBuf>,
                _: &Option<PathBuf>,
                _: &diagnostics::registry::Registry)
                -> Option<(Input, Option<PathBuf>)> {
        panic!("No input supplied to RustFmt");
    }

    fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> {
        let mut config_option = None;
        swap(&mut self.config, &mut config_option);
        let config = config_option.unwrap();
        let result = self.result.clone();

        let mut control = driver::CompileController::basic();
        control.after_parse.stop = Compilation::Stop;
        control.after_parse.callback = Box::new(move |state| {
            let krate = state.krate.unwrap();
            let codemap = state.session.codemap();
            let mut file_map = fmt_ast(krate, codemap, &*config);
            // For some reason, the codemap does not include terminating
            // newlines so we must add one on for each file. This is sad.
            filemap::append_newlines(&mut file_map);

            *result.borrow_mut() = Some(file_map);
        });

        control
    }
}

pub fn format(args: Vec<String>, config: Box<Config>) -> FileMap {
    let result = Rc::new(RefCell::new(None));
    {
        let mut call_ctxt = RustFmtCalls { config: Some(config), result: result.clone() };
        rustc_driver::run_compiler(&args, &mut call_ctxt);
    }

    // Peel the union.
    Rc::try_unwrap(result).ok().unwrap().into_inner().unwrap()
}

// args are the arguments passed on the command line, generally passed through
// to the compiler.
// write_mode determines what happens to the result of running rustfmt, see
// WriteMode.
pub fn run(args: Vec<String>, write_mode: WriteMode, config: Box<Config>) {
    // FIXME: we probs don't need a full clone
    let config_clone = (&config).clone();
    let mut result = format(args, config);

    println!("{}", fmt_lines(&mut result, &config_clone));

    let write_result = filemap::write_all_files(&result, write_mode, &config_clone);

    match write_result {
        Err(msg) => println!("Error writing files: {}", msg),
        Ok(result) => {
            if let WriteMode::Return(callback) = write_mode {
                callback(result);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! This is a library made for interacting with the Minecraft protocl
//! (MCMODERN only, not MCPE.)
//!
//! It is mostly a low-level library, its goals are to
//! handle everything network related, but nothing beyond that. For example
//! this library does not support any types beyond ones found in standard Rust,
//! this results in certain packets that contain compound datatypes not having
//! their complex fields serialized by this library, but instead handing the
//! raw binary data to consumers of this library to parse however they wish.
//! One example of this is packets that contain NBT data, the packets are read
//! but the NBT data is not in any way parsed by this library.
//!
//! This library currently only supports the client side of the connection,
//! but servers may be supported in the future as well, since we already have
//! all the packet definitions.
//!
//! Currently the library is entirely synchronous, requiring consumers to handle
//! concurrency however they wish. It would be cool to add an asynchronous API
//! though, maybe using mio.
//!
//! The library nominally supports every packet used in MCMODERN, but the goal
//! is still to add lots more helper functions and other useful things.
//!
//! The library does not yet have any stable releases, not because it may
//! contain bugs (which it certainly does,) but because the API may be
//! significantly restructured without warning.
//!
//! # Examples
//!
//! Connecting to a remote server as an authenticated user, printing all chat
//! messages, and then echoing back messages that appear not to be written by us
//! (else we'd get into an infinite loop echoing our own messages.)
//!
//! ```rust,no_run
//! use ozelot::{yggdrasil, Client, client_send, utils};
//! use ozelot::client_recv::ClientboundPacket;
//!
//! let (access_token, _, username, uuid) = yggdrasil::authenticate("my_email@example.com", "my_password").unwrap();
//!
//! /* By using connect_authenticated, auto_handle will be true and thus ozelot
//!  * will respond to keepalives automatically */
//! let mut client = Client::connect_authenticated("minecraft.example.com", 25565,
//!                           &access_token, &username, &uuid).unwrap();
//!
//! 'main: loop {
//!     let packets = client.read().unwrap();
//!     for packet in packets {
//!         match packet {
//!         ClientboundPacket::PlayDisconnect(ref p) => {
//!             println!("Disconnected, reason: {}", utils::chat_to_str(p.get_reason()));
//!             break 'main;
//!         },
//!         ClientboundPacket::ChatMessage(ref p) => {
//!             let msg = utils::chat_to_str(p.get_chat());
//!             println!("{}", msg);
//!             if !msg.contains(&username) {
//!                 /* Since we don't want an infinite loop, we don't echo back
//!                  * our own messages. We say that a received message wasn't
//!                  * written by us if it doesn't contain our username
//!                  *
//!                  * Note that this echoes back the raw chat message, that is
//!                  * playername and everything, and also non-chat messages. */
//!                 let response = client_send::ChatMessage::new(msg);
//!                 client.send(response).unwrap();
//!             }
//!         },
//!         /* We throw away all other packets */
//!         _ => (),
//!         }
//!     }
//! }
//! ```
extern crate byteorder;
extern crate flate2;
extern crate netbuf;
extern crate openssl;
extern crate reqwest; /* Holy fuck the dependencies needed just to make 2
                         HTTP POST requests ... */
extern crate rustc_serialize;

#[macro_use]
mod macros;
mod client;
pub mod yggdrasil;
pub mod utils;
pub mod read;
pub mod write;
pub mod client_recv;
pub mod client_send;
#[cfg(test)]
mod tests;

pub use client::Client;

use std::io;

use flate2::Compression;

const COMPRESSION_LEVEL: Compression = Compression::Default;
/// The protocol version supported by this version of ozelot
pub const PROTOCOL_VERSION: i32 = 316;

/// FIXME temporary struct until u128 lands in stable rust, used for uuids
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[allow(non_camel_case_types)]
pub struct u128(u64, u64);

/// This tracks which state of play the client is in. The value of this changes
/// the meaning of the different packet ids.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClientState {
    Handshake,
    Status,
    Login,
    Play,
}

/// Trait for structs/packets that can be sent over the network connection
pub trait Sendable {
    fn to_u8(&self) -> io::Result<Vec<u8>>;
    fn get_state() -> ClientState;
    fn get_id() -> i32;
}

<commit_msg>Add link to the repository page in the rustdocs<commit_after>//! [(Link to repository page.)](https://github.com/C4K3/Ozelot)
//!
//! This is a library made for interacting with the Minecraft protocl
//! (MCMODERN only, not MCPE.)
//!
//! It is mostly a low-level library, its goals are to
//! handle everything network related, but nothing beyond that. For example
//! this library does not support any types beyond ones found in standard Rust,
//! this results in certain packets that contain compound datatypes not having
//! their complex fields serialized by this library, but instead handing the
//! raw binary data to consumers of this library to parse however they wish.
//! One example of this is packets that contain NBT data, the packets are read
//! but the NBT data is not in any way parsed by this library.
//!
//! This library currently only supports the client side of the connection,
//! but servers may be supported in the future as well, since we already have
//! all the packet definitions.
//!
//! Currently the library is entirely synchronous, requiring consumers to handle
//! concurrency however they wish. It would be cool to add an asynchronous API
//! though, maybe using mio.
//!
//! The library nominally supports every packet used in MCMODERN, but the goal
//! is still to add lots more helper functions and other useful things.
//!
//! The library does not yet have any stable releases, not because it may
//! contain bugs (which it certainly does,) but because the API may be
//! significantly restructured without warning.
//!
//! # Examples
//!
//! Connecting to a remote server as an authenticated user, printing all chat
//! messages, and then echoing back messages that appear not to be written by us
//! (else we'd get into an infinite loop echoing our own messages.)
//!
//! ```rust,no_run
//! use ozelot::{yggdrasil, Client, client_send, utils};
//! use ozelot::client_recv::ClientboundPacket;
//!
//! let (access_token, _, username, uuid) = yggdrasil::authenticate("my_email@example.com", "my_password").unwrap();
//!
//! /* By using connect_authenticated, auto_handle will be true and thus ozelot
//!  * will respond to keepalives automatically */
//! let mut client = Client::connect_authenticated("minecraft.example.com", 25565,
//!                           &access_token, &username, &uuid).unwrap();
//!
//! 'main: loop {
//!     let packets = client.read().unwrap();
//!     for packet in packets {
//!         match packet {
//!         ClientboundPacket::PlayDisconnect(ref p) => {
//!             println!("Disconnected, reason: {}", utils::chat_to_str(p.get_reason()));
//!             break 'main;
//!         },
//!         ClientboundPacket::ChatMessage(ref p) => {
//!             let msg = utils::chat_to_str(p.get_chat());
//!             println!("{}", msg);
//!             if !msg.contains(&username) {
//!                 /* Since we don't want an infinite loop, we don't echo back
//!                  * our own messages. We say that a received message wasn't
//!                  * written by us if it doesn't contain our username
//!                  *
//!                  * Note that this echoes back the raw chat message, that is
//!                  * playername and everything, and also non-chat messages. */
//!                 let response = client_send::ChatMessage::new(msg);
//!                 client.send(response).unwrap();
//!             }
//!         },
//!         /* We throw away all other packets */
//!         _ => (),
//!         }
//!     }
//! }
//! ```
extern crate byteorder;
extern crate flate2;
extern crate netbuf;
extern crate openssl;
extern crate reqwest; /* Holy fuck the dependencies needed just to make 2
                         HTTP POST requests ... */
extern crate rustc_serialize;

#[macro_use]
mod macros;
mod client;
pub mod yggdrasil;
pub mod utils;
pub mod read;
pub mod write;
pub mod client_recv;
pub mod client_send;
#[cfg(test)]
mod tests;

pub use client::Client;

use std::io;

use flate2::Compression;

const COMPRESSION_LEVEL: Compression = Compression::Default;
/// The protocol version supported by this version of ozelot
pub const PROTOCOL_VERSION: i32 = 316;

/// FIXME temporary struct until u128 lands in stable rust, used for uuids
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[allow(non_camel_case_types)]
pub struct u128(u64, u64);

/// This tracks which state of play the client is in. The value of this changes
/// the meaning of the different packet ids.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClientState {
    Handshake,
    Status,
    Login,
    Play,
}

/// Trait for structs/packets that can be sent over the network connection
pub trait Sendable {
    fn to_u8(&self) -> io::Result<Vec<u8>>;
    fn get_state() -> ClientState;
    fn get_id() -> i32;
}

<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Crate docs

#![allow(bad_style, raw_pointer_derive, overflowing_literals, improper_ctypes)]
#![crate_type = "rlib"]
#![crate_name = "libc"]
#![cfg_attr(dox, feature(no_core, lang_items))]
#![cfg_attr(dox, no_core)]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico")]

#![cfg_attr(all(target_os = "linux", target_arch = "x86_64"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/x86_64-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "x86"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/i686-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "arm"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/arm-unknown-linux-gnueabihf"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "mips"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/mips-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "aarch64"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/aarch64-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_env = "musl"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/x86_64-unknown-linux-musl"
))]
#![cfg_attr(all(target_os = "macos", target_arch = "x86_64"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/x86_64-apple-darwin"
))]
#![cfg_attr(all(target_os = "macos", target_arch = "x86"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/i686-apple-darwin"
))]
#![cfg_attr(all(windows, target_arch = "x86_64", target_env = "gnu"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/x86_64-pc-windows-gnu"
))]
#![cfg_attr(all(windows, target_arch = "x86", target_env = "gnu"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/i686-pc-windows-gnu"
))]
#![cfg_attr(all(windows, target_arch = "x86_64", target_env = "msvc"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/x86_64-pc-windows-msvc"
))]
#![cfg_attr(all(windows, target_arch = "x86", target_env = "msvc"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/i686-pc-windows-msvc"
))]
#![cfg_attr(all(target_os = "android"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/arm-linux-androideabi"
))]

// Attributes needed when building as part of the standard library
#![cfg_attr(stdbuild, feature(no_std, core, core_slice_ext, staged_api))]
#![cfg_attr(stdbuild, no_std)]
#![cfg_attr(stdbuild, staged_api)]
#![cfg_attr(stdbuild, allow(warnings))]
#![cfg_attr(stdbuild, unstable(feature = "libc",
                               reason = "use `libc` from crates.io",
                               issue = "27783"))]

#[cfg(all(not(stdbuild), not(dox)))]
extern crate std as core;

#[macro_use] mod macros;
mod dox;

// Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help enable
// more optimization opportunities around it recognizing things like
// malloc/free.
#[repr(u8)]
pub enum c_void {
    // Two dummy variants so the #[repr] attribute can be used.
    #[doc(hidden)]
    __variant1,
    #[doc(hidden)]
    __variant2,
}

pub type int8_t = i8;
pub type int16_t = i16;
pub type int32_t = i32;
pub type int64_t = i64;
pub type uint8_t = u8;
pub type uint16_t = u16;
pub type uint32_t = u32;
pub type uint64_t = u64;

pub type c_schar = i8;
pub type c_uchar = u8;
pub type c_short = i16;
pub type c_ushort = u16;
pub type c_int = i32;
pub type c_uint = u32;
pub type c_float = f32;
pub type c_double = f64;
pub type c_longlong = i64;
pub type c_ulonglong = u64;
pub type intmax_t = i64;
pub type uintmax_t = u64;

pub type size_t = usize;
pub type ptrdiff_t = isize;
pub type intptr_t = isize;
pub type uintptr_t = usize;
pub type ssize_t = isize;

pub enum FILE {}
pub enum fpos_t {} // TODO: fill this out with a struct

extern {
    pub fn isalnum(c: c_int) -> c_int;
    pub fn isalpha(c: c_int) -> c_int;
    pub fn iscntrl(c: c_int) -> c_int;
    pub fn isdigit(c: c_int) -> c_int;
    pub fn isgraph(c: c_int) -> c_int;
    pub fn islower(c: c_int) -> c_int;
    pub fn isprint(c: c_int) -> c_int;
    pub fn ispunct(c: c_int) -> c_int;
    pub fn isspace(c: c_int) -> c_int;
    pub fn isupper(c: c_int) -> c_int;
    pub fn isxdigit(c: c_int) -> c_int;
    pub fn tolower(c: c_int) -> c_int;
    pub fn toupper(c: c_int) -> c_int;

    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "fopen$UNIX2003")]
    pub fn fopen(filename: *const c_char,
                 mode: *const c_char) -> *mut FILE;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "freopen$UNIX2003")]
    pub fn freopen(filename: *const c_char, mode: *const c_char,
                   file: *mut FILE) -> *mut FILE;
    pub fn fflush(file: *mut FILE) -> c_int;
    pub fn fclose(file: *mut FILE) -> c_int;
    pub fn remove(filename: *const c_char) -> c_int;
    pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int;
    pub fn tmpfile() -> *mut FILE;
    pub fn setvbuf(stream: *mut FILE,
                   buffer: *mut c_char,
                   mode: c_int,
                   size: size_t) -> c_int;
    pub fn setbuf(stream: *mut FILE, buf: *mut c_char);
    pub fn fgetc(stream: *mut FILE) -> c_int;
    pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char;
    pub fn fputc(c: c_int, stream: *mut FILE) -> c_int;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "fputs$UNIX2003")]
    pub fn fputs(s: *const c_char, stream: *mut FILE)-> c_int;
    pub fn puts(s: *const c_char) -> c_int;
    pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int;
    pub fn fread(ptr: *mut c_void,
                 size: size_t,
                 nobj: size_t,
                 stream: *mut FILE)
                 -> size_t;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "fwrite$UNIX2003")]
    pub fn fwrite(ptr: *const c_void,
                  size: size_t,
                  nobj: size_t,
                  stream: *mut FILE)
                  -> size_t;
    pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int;
    pub fn ftell(stream: *mut FILE) -> c_long;
    pub fn rewind(stream: *mut FILE);
    pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int;
    pub fn fsetpos(stream: *mut FILE, ptr: *const fpos_t) -> c_int;
    pub fn feof(stream: *mut FILE) -> c_int;
    pub fn ferror(stream: *mut FILE) -> c_int;
    pub fn perror(s: *const c_char);
    pub fn atoi(s: *const c_char) -> c_int;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "strtod$UNIX2003")]
    pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double;
    pub fn strtol(s: *const c_char,
                  endp: *mut *mut c_char, base: c_int) -> c_long;
    pub fn strtoul(s: *const c_char, endp: *mut *mut c_char,
                   base: c_int) -> c_ulong;
    pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void;
    pub fn malloc(size: size_t) -> *mut c_void;
    pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void;
    pub fn free(p: *mut c_void);
    pub fn exit(status: c_int) -> !;
    pub fn _exit(status: c_int) -> !;
    pub fn atexit(cb: extern fn()) -> c_int;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "system$UNIX2003")]
    pub fn system(s: *const c_char) -> c_int;
    pub fn getenv(s: *const c_char) -> *mut c_char;

    pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char;
    pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t)
                   -> *mut c_char;
    pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char;
    pub fn strncat(s: *mut c_char, ct: *const c_char, n: size_t) -> *mut c_char;
    pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int;
    pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int;
    pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int;
    pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char;
    pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char;
    pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t;
    pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t;
    pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char;
    pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char;
    pub fn strlen(cs: *const c_char) -> size_t;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "strerror$UNIX2003")]
    pub fn strerror(n: c_int) -> *mut c_char;
    pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char;
    pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t;
    pub fn wcslen(buf: *const wchar_t) -> size_t;

    pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int;
    pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void;
}

// These are all inline functions on android, so they end up just being entirely
// missing on that platform.
#[cfg(not(target_os = "android"))]
extern {
    pub fn abs(i: c_int) -> c_int;
    pub fn atof(s: *const c_char) -> c_double;
    pub fn labs(i: c_long) -> c_long;
    pub fn rand() -> c_int;
    pub fn srand(seed: c_uint);
}

cfg_if! {
    if #[cfg(windows)] {
        mod windows;
        pub use windows::*;
    } else {
        mod unix;
        pub use unix::*;
    }
}
<commit_msg>Remove reference to raw_pointer_derive lint<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Crate docs

#![allow(bad_style, overflowing_literals, improper_ctypes)]
#![crate_type = "rlib"]
#![crate_name = "libc"]
#![cfg_attr(dox, feature(no_core, lang_items))]
#![cfg_attr(dox, no_core)]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico")]

#![cfg_attr(all(target_os = "linux", target_arch = "x86_64"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/x86_64-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "x86"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/i686-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "arm"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/arm-unknown-linux-gnueabihf"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "mips"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/mips-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_arch = "aarch64"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/aarch64-unknown-linux-gnu"
))]
#![cfg_attr(all(target_os = "linux", target_env = "musl"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/x86_64-unknown-linux-musl"
))]
#![cfg_attr(all(target_os = "macos", target_arch = "x86_64"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/x86_64-apple-darwin"
))]
#![cfg_attr(all(target_os = "macos", target_arch = "x86"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/i686-apple-darwin"
))]
#![cfg_attr(all(windows, target_arch = "x86_64", target_env = "gnu"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/x86_64-pc-windows-gnu"
))]
#![cfg_attr(all(windows, target_arch = "x86", target_env = "gnu"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/i686-pc-windows-gnu"
))]
#![cfg_attr(all(windows, target_arch = "x86_64", target_env = "msvc"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/x86_64-pc-windows-msvc"
))]
#![cfg_attr(all(windows, target_arch = "x86", target_env = "msvc"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/i686-pc-windows-msvc"
))]
#![cfg_attr(all(target_os = "android"), doc(
    html_root_url = "https://doc.rust-lang.org/libc/arm-linux-androideabi"
))]

// Attributes needed when building as part of the standard library
#![cfg_attr(stdbuild, feature(no_std, core, core_slice_ext, staged_api))]
#![cfg_attr(stdbuild, no_std)]
#![cfg_attr(stdbuild, staged_api)]
#![cfg_attr(stdbuild, allow(warnings))]
#![cfg_attr(stdbuild, unstable(feature = "libc",
                               reason = "use `libc` from crates.io",
                               issue = "27783"))]

#[cfg(all(not(stdbuild), not(dox)))]
extern crate std as core;

#[macro_use] mod macros;
mod dox;

// Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help enable
// more optimization opportunities around it recognizing things like
// malloc/free.
#[repr(u8)]
pub enum c_void {
    // Two dummy variants so the #[repr] attribute can be used.
    #[doc(hidden)]
    __variant1,
    #[doc(hidden)]
    __variant2,
}

pub type int8_t = i8;
pub type int16_t = i16;
pub type int32_t = i32;
pub type int64_t = i64;
pub type uint8_t = u8;
pub type uint16_t = u16;
pub type uint32_t = u32;
pub type uint64_t = u64;

pub type c_schar = i8;
pub type c_uchar = u8;
pub type c_short = i16;
pub type c_ushort = u16;
pub type c_int = i32;
pub type c_uint = u32;
pub type c_float = f32;
pub type c_double = f64;
pub type c_longlong = i64;
pub type c_ulonglong = u64;
pub type intmax_t = i64;
pub type uintmax_t = u64;

pub type size_t = usize;
pub type ptrdiff_t = isize;
pub type intptr_t = isize;
pub type uintptr_t = usize;
pub type ssize_t = isize;

pub enum FILE {}
pub enum fpos_t {} // TODO: fill this out with a struct

extern {
    pub fn isalnum(c: c_int) -> c_int;
    pub fn isalpha(c: c_int) -> c_int;
    pub fn iscntrl(c: c_int) -> c_int;
    pub fn isdigit(c: c_int) -> c_int;
    pub fn isgraph(c: c_int) -> c_int;
    pub fn islower(c: c_int) -> c_int;
    pub fn isprint(c: c_int) -> c_int;
    pub fn ispunct(c: c_int) -> c_int;
    pub fn isspace(c: c_int) -> c_int;
    pub fn isupper(c: c_int) -> c_int;
    pub fn isxdigit(c: c_int) -> c_int;
    pub fn tolower(c: c_int) -> c_int;
    pub fn toupper(c: c_int) -> c_int;

    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "fopen$UNIX2003")]
    pub fn fopen(filename: *const c_char,
                 mode: *const c_char) -> *mut FILE;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "freopen$UNIX2003")]
    pub fn freopen(filename: *const c_char, mode: *const c_char,
                   file: *mut FILE) -> *mut FILE;
    pub fn fflush(file: *mut FILE) -> c_int;
    pub fn fclose(file: *mut FILE) -> c_int;
    pub fn remove(filename: *const c_char) -> c_int;
    pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int;
    pub fn tmpfile() -> *mut FILE;
    pub fn setvbuf(stream: *mut FILE,
                   buffer: *mut c_char,
                   mode: c_int,
                   size: size_t) -> c_int;
    pub fn setbuf(stream: *mut FILE, buf: *mut c_char);
    pub fn fgetc(stream: *mut FILE) -> c_int;
    pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char;
    pub fn fputc(c: c_int, stream: *mut FILE) -> c_int;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "fputs$UNIX2003")]
    pub fn fputs(s: *const c_char, stream: *mut FILE)-> c_int;
    pub fn puts(s: *const c_char) -> c_int;
    pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int;
    pub fn fread(ptr: *mut c_void,
                 size: size_t,
                 nobj: size_t,
                 stream: *mut FILE)
                 -> size_t;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "fwrite$UNIX2003")]
    pub fn fwrite(ptr: *const c_void,
                  size: size_t,
                  nobj: size_t,
                  stream: *mut FILE)
                  -> size_t;
    pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int;
    pub fn ftell(stream: *mut FILE) -> c_long;
    pub fn rewind(stream: *mut FILE);
    pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int;
    pub fn fsetpos(stream: *mut FILE, ptr: *const fpos_t) -> c_int;
    pub fn feof(stream: *mut FILE) -> c_int;
    pub fn ferror(stream: *mut FILE) -> c_int;
    pub fn perror(s: *const c_char);
    pub fn atoi(s: *const c_char) -> c_int;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "strtod$UNIX2003")]
    pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double;
    pub fn strtol(s: *const c_char,
                  endp: *mut *mut c_char, base: c_int) -> c_long;
    pub fn strtoul(s: *const c_char, endp: *mut *mut c_char,
                   base: c_int) -> c_ulong;
    pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void;
    pub fn malloc(size: size_t) -> *mut c_void;
    pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void;
    pub fn free(p: *mut c_void);
    pub fn exit(status: c_int) -> !;
    pub fn _exit(status: c_int) -> !;
    pub fn atexit(cb: extern fn()) -> c_int;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "system$UNIX2003")]
    pub fn system(s: *const c_char) -> c_int;
    pub fn getenv(s: *const c_char) -> *mut c_char;

    pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char;
    pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t)
                   -> *mut c_char;
    pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char;
    pub fn strncat(s: *mut c_char, ct: *const c_char, n: size_t) -> *mut c_char;
    pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int;
    pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int;
    pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int;
    pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char;
    pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char;
    pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t;
    pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t;
    pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char;
    pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char;
    pub fn strlen(cs: *const c_char) -> size_t;
    #[cfg_attr(all(target_os = "macos", target_arch = "x86"),
               link_name = "strerror$UNIX2003")]
    pub fn strerror(n: c_int) -> *mut c_char;
    pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char;
    pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t;
    pub fn wcslen(buf: *const wchar_t) -> size_t;

    pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int;
    pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void;
}

// These are all inline functions on android, so they end up just being entirely
// missing on that platform.
#[cfg(not(target_os = "android"))]
extern {
    pub fn abs(i: c_int) -> c_int;
    pub fn atof(s: *const c_char) -> c_double;
    pub fn labs(i: c_long) -> c_long;
    pub fn rand() -> c_int;
    pub fn srand(seed: c_uint);
}

cfg_if! {
    if #[cfg(windows)] {
        mod windows;
        pub use windows::*;
    } else {
        mod unix;
        pub use unix::*;
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![allow(unstable)]

//! Experimental dynamic OOP system.
//!
//! There's not much documentation here. See the `README` and tests.

use std::cell::RefCell;
use std::marker;

#[doc(hidden)]
#[derive(Copy)]
pub struct Proxy<T>;

#[doc(hidden)]
pub trait ReflectImpl<Trait: ?Sized> {
    type CtorArg;
    unsafe fn get_class(self) -> Class<Trait, Self::CtorArg>;
}

pub struct Class<Trait: ?Sized, Arg>
    (#[doc(hidden)] pub RefCell<Class_<Trait, Arg>>);

#[doc(hidden)]
pub struct Class_<Trait: ?Sized, Arg> {
    pub vtable: *mut (),
    pub ctor: unsafe fn(Arg) -> *mut (),
    pub size: usize,
    pub align: usize,
}

// derive(Clone) can't handle the ?Sized parameter
impl<Trait: ?Sized, Arg> Clone for Class_<Trait, Arg> {
    fn clone(&self) -> Class_<Trait, Arg> {
        Class_ {
            ctor: self.ctor,
            vtable: self.vtable,
            size: self.size,
            align: self.align,
        }
    }
}

pub struct Instance<'cls, Trait: ?Sized + 'cls> {
    // In lieu of &'cls Class<...>. The raw pointer can't be
    // dereferenced from safe code, which is important because
    // we've erased the constructor's argument type.
    marker: marker::ContravariantLifetime<'cls>,
    #[doc(hidden)] pub __class__: *const Class<Trait, ()>,
    #[doc(hidden)] pub __data__: *mut (),
}

impl<Trait: ?Sized, Arg> Class<Trait, Arg> {
    pub fn of<Impl>() -> Class<Trait, Arg>
        where Impl: Copy,
              Proxy<Impl>: ReflectImpl<Trait, CtorArg=Arg>,
    {
        let prx: Proxy<Impl> = Proxy;
        unsafe { prx.get_class() }
    }

    pub fn new<'cls>(&'cls self, arg: Arg) -> Instance<'cls, Trait> {
        use std::mem;
        unsafe {
            Instance {
                __class__: mem::transmute::<_, *const Class<Trait, ()>>(self),
                __data__: (self.0.borrow().ctor)(arg),
                marker: marker::ContravariantLifetime,
            }
        }
    }

    pub unsafe fn override_methods(&self, replacement: &Class<Trait, Arg>) {
        *self.0.borrow_mut() = replacement.0.borrow().clone();
    }
}

#[macro_export]
macro_rules! interface {
    ($Trait:ty) => (
        impl<'cls> ::std::ops::Deref for $crate::Instance<'cls, $Trait + 'cls> {
            type Target = $Trait + 'cls;

            fn deref<'a>(&'a self) -> &'a ($Trait + 'cls) {
                use std::{mem, raw};
                unsafe {
                    mem::transmute(raw::TraitObject {
                        data: self.__data__,
                        vtable: (*self.__class__).0.borrow().vtable,
                    })
                }
            }
        }

        #[unsafe_destructor]
        impl<'cls> ::std::ops::Drop for $crate::Instance<'cls, $Trait + 'cls> {
            fn drop(&mut self) {
                // Virtual destructors are a bit messed up in Rust at the
                // moment. We avoid the problem by requiring Impl: Copy on
                // Class::of::<Impl>().  So here in drop we just free the
                // memory.

                unsafe {
                    let (size, align) = {
                        let cls = (*self.__class__).0.borrow();
                        (cls.size, cls.align)
                    };
                    std::rt::heap::deallocate(self.__data__ as *mut u8, size, align);
                }
            }
        }
    );
}

#[macro_export]
macro_rules! constructor {
    ($Impl:ty as $Trait:ty,
        fn new($arg:ident: $CtorArg:ty) -> ... $body:block
    ) => (
        impl<'a> $crate::ReflectImpl<$Trait + 'a> for $crate::Proxy<$Impl> {
            type CtorArg = $CtorArg;

            unsafe fn get_class(self) -> $crate::Class<$Trait + 'a, $CtorArg> {
                use std::{mem, raw};
                use std::ptr;
                use std::cell::RefCell;

                fn ctor($arg: $CtorArg) -> $Impl
                    $body

                unsafe fn box_ctor(arg: $CtorArg) -> *mut () {
                    let obj = std::rt::heap::allocate(mem::size_of::<$Impl>(),
                        mem::align_of::<$Impl>());
                    ptr::write(obj as *mut $Impl, ctor(arg));
                    obj as *mut ()
                }

                $crate::Class(RefCell::new($crate::Class_ {
                    ctor: box_ctor,
                    vtable: {
                        let x: $Impl = mem::uninitialized();
                        let vtable = {
                            let obj: &($Trait + 'static) = &x;
                            let obj: raw::TraitObject = mem::transmute(obj);
                            obj.vtable
                        };
                        mem::forget(x);
                        vtable
                    },
                    size: mem::size_of::<$Impl>(),
                    align: mem::align_of::<$Impl>(),
                }))
            }
        }
    );
}
<commit_msg>Move Drop for Instance outside the macro<commit_after>#![feature(unsafe_destructor)]

#![deny(warnings)]
#![allow(unstable)]

//! Experimental dynamic OOP system.
//!
//! There's not much documentation here. See the `README` and tests.

use std::cell::RefCell;
use std::marker;

#[doc(hidden)]
#[derive(Copy)]
pub struct Proxy<T>;

#[doc(hidden)]
pub trait ReflectImpl<Trait: ?Sized> {
    type CtorArg;
    unsafe fn get_class(self) -> Class<Trait, Self::CtorArg>;
}

pub struct Class<Trait: ?Sized, Arg>
    (#[doc(hidden)] pub RefCell<Class_<Trait, Arg>>);

#[doc(hidden)]
pub struct Class_<Trait: ?Sized, Arg> {
    pub vtable: *mut (),
    pub ctor: unsafe fn(Arg) -> *mut (),
    pub size: usize,
    pub align: usize,
}

// derive(Clone) can't handle the ?Sized parameter
impl<Trait: ?Sized, Arg> Clone for Class_<Trait, Arg> {
    fn clone(&self) -> Class_<Trait, Arg> {
        Class_ {
            ctor: self.ctor,
            vtable: self.vtable,
            size: self.size,
            align: self.align,
        }
    }
}

pub struct Instance<'cls, Trait: ?Sized + 'cls> {
    // In lieu of &'cls Class<...>. The raw pointer can't be
    // dereferenced from safe code, which is important because
    // we've erased the constructor's argument type.
    marker: marker::ContravariantLifetime<'cls>,
    #[doc(hidden)] pub __class__: *const Class<Trait, ()>,
    #[doc(hidden)] pub __data__: *mut (),
}

#[unsafe_destructor]
impl<'cls, Trait: ?Sized> Drop for Instance<'cls, Trait> {
    fn drop(&mut self) {
        // Virtual destructors are a bit messed up in Rust at the
        // moment. We avoid the problem by requiring Impl: Copy on
        // Class::of::<Impl>().  So here in drop we just free the
        // memory.

        unsafe {
            let (size, align) = {
                let cls = (*self.__class__).0.borrow();
                (cls.size, cls.align)
            };
            std::rt::heap::deallocate(self.__data__ as *mut u8, size, align);
        }
    }
}

impl<Trait: ?Sized, Arg> Class<Trait, Arg> {
    pub fn of<Impl>() -> Class<Trait, Arg>
        where Impl: Copy,
              Proxy<Impl>: ReflectImpl<Trait, CtorArg=Arg>,
    {
        let prx: Proxy<Impl> = Proxy;
        unsafe { prx.get_class() }
    }

    pub fn new<'cls>(&'cls self, arg: Arg) -> Instance<'cls, Trait> {
        use std::mem;
        unsafe {
            Instance {
                __class__: mem::transmute::<_, *const Class<Trait, ()>>(self),
                __data__: (self.0.borrow().ctor)(arg),
                marker: marker::ContravariantLifetime,
            }
        }
    }

    pub unsafe fn override_methods(&self, replacement: &Class<Trait, Arg>) {
        *self.0.borrow_mut() = replacement.0.borrow().clone();
    }
}

#[macro_export]
macro_rules! interface {
    ($Trait:ty) => (
        impl<'cls> ::std::ops::Deref for $crate::Instance<'cls, $Trait + 'cls> {
            type Target = $Trait + 'cls;

            fn deref<'a>(&'a self) -> &'a ($Trait + 'cls) {
                use std::{mem, raw};
                unsafe {
                    mem::transmute(raw::TraitObject {
                        data: self.__data__,
                        vtable: (*self.__class__).0.borrow().vtable,
                    })
                }
            }
        }
    );
}

#[macro_export]
macro_rules! constructor {
    ($Impl:ty as $Trait:ty,
        fn new($arg:ident: $CtorArg:ty) -> ... $body:block
    ) => (
        impl<'a> $crate::ReflectImpl<$Trait + 'a> for $crate::Proxy<$Impl> {
            type CtorArg = $CtorArg;

            unsafe fn get_class(self) -> $crate::Class<$Trait + 'a, $CtorArg> {
                use std::{mem, raw};
                use std::ptr;
                use std::cell::RefCell;

                fn ctor($arg: $CtorArg) -> $Impl
                    $body

                unsafe fn box_ctor(arg: $CtorArg) -> *mut () {
                    let obj = std::rt::heap::allocate(mem::size_of::<$Impl>(),
                        mem::align_of::<$Impl>());
                    ptr::write(obj as *mut $Impl, ctor(arg));
                    obj as *mut ()
                }

                $crate::Class(RefCell::new($crate::Class_ {
                    ctor: box_ctor,
                    vtable: {
                        let x: $Impl = mem::uninitialized();
                        let vtable = {
                            let obj: &($Trait + 'static) = &x;
                            let obj: raw::TraitObject = mem::transmute(obj);
                            obj.vtable
                        };
                        mem::forget(x);
                        vtable
                    },
                    size: mem::size_of::<$Impl>(),
                    align: mem::align_of::<$Impl>(),
                }))
            }
        }
    );
}
<|endoftext|>


<commit_before>#![no_std]

use core::usize::MAX as USIZE_MAX;

// https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use

#[cfg(target_pointer_width = "32")]
static OFFSET: usize = 1013904223;
#[cfg(target_pointer_width = "32")]
static MULTIPLIER: usize = 1664525;

#[cfg(target_pointer_width = "64")]
static OFFSET: usize = 1442695040888963407;
#[cfg(target_pointer_width = "64")]
static MULTIPLIER: usize = 6364136223846793005;

static mut SEED: usize = USIZE_MAX / 2usize;

// http://indiegamr.com/generate-repeatable-random-numbers-in-js/
#[inline(always)]
pub fn rand() -> usize {
    unsafe {
        SEED = (MULTIPLIER * SEED + OFFSET) % USIZE_MAX;
        SEED
    }
}

#[inline(always)]
pub fn srand(s: usize) {
    unsafe {
        SEED = s;
    }
}

#[test]
fn test_rand() {
    if cfg!(target_pointer_width = "64") {
        assert_eq!(rand(), 4301930853896946210);
        srand(4301930853896946210);
        assert_eq!(rand(), 3578485316352917321);
    } else if cfg!(target_pointer_width = "32") {
        assert_eq!(rand(), 3159723346);
        srand(3159723346);
        assert_eq!(rand(), 2954349705);
    }
}
<commit_msg>added struct<commit_after>#![no_std]

use core::usize::MAX as USIZE_MAX;

// https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
#[cfg(target_pointer_width = "32")]
static OFFSET: usize = 1013904223;
#[cfg(target_pointer_width = "32")]
static MULTIPLIER: usize = 1664525;

#[cfg(target_pointer_width = "64")]
static OFFSET: usize = 1442695040888963407;
#[cfg(target_pointer_width = "64")]
static MULTIPLIER: usize = 6364136223846793005;

static mut SEED: usize = USIZE_MAX / 2;

pub struct Random {
    _seed: usize,
}

impl Random {
    #[inline(always)]
    pub fn new() -> Random {
        Random {
            _seed: USIZE_MAX / 2,
        }
    }

    // http://indiegamr.com/generate-repeatable-random-numbers-in-js/
    #[inline(always)]
    pub fn rand(&mut self) -> usize {
        self._seed = (MULTIPLIER * self._seed + OFFSET) % USIZE_MAX;
        self._seed
    }

    #[inline(always)]
    pub fn seed(&mut self, s: usize) {
        self._seed = s;
    }
}

#[test]
fn test_random_struct() {
    let mut random = Random::new();

    if cfg!(target_pointer_width = "64") {
        assert_eq!(random.rand(), 4301930853896946210);
        random.seed(4301930853896946210);
        assert_eq!(random.rand(), 3578485316352917321);
    } else if cfg!(target_pointer_width = "32") {
        assert_eq!(random.rand(), 3159723346);
        random.seed(3159723346);
        assert_eq!(random.rand(), 2954349705);
    }
}

#[inline(always)]
pub fn rand() -> usize {
    unsafe {
        SEED = (MULTIPLIER * SEED + OFFSET) % USIZE_MAX;
        SEED
    }
}
#[inline(always)]
pub fn seed(s: usize) {
    unsafe {
        SEED = s;
    }
}

#[test]
fn test_random() {
    if cfg!(target_pointer_width = "64") {
        assert_eq!(rand(), 4301930853896946210);
        seed(4301930853896946210);
        assert_eq!(rand(), 3578485316352917321);
    } else if cfg!(target_pointer_width = "32") {
        assert_eq!(rand(), 3159723346);
        seed(3159723346);
        assert_eq!(rand(), 2954349705);
    }
}
<|endoftext|>