<commit_before>extern crate draw_queue;

use std::cmp::Ordering;
use gfx;

pub type FlushError = gfx::DrawError<gfx::batch::OutOfBounds>;

pub trait AbstractPhase<D: gfx::Device, E, Z> {
    /// Check if it makes sense to draw this entity
    fn does_apply(&self, &E) -> bool;
    /// Add an entity to the queue
    fn enqueue(&mut self, &E, Z, &mut gfx::batch::Context<D::Resources>)
               -> Result<(), gfx::batch::Error>;
    /// Flush the queue into a given renderer
    fn flush(&mut self, &gfx::Frame<D::Resources>,
             &gfx::batch::Context<D::Resources>,
             &mut gfx::Renderer<D::Resources, D::CommandBuffer>)
             -> Result<(), FlushError>;
}

struct Object<S, P: gfx::shade::ShaderParam> {
    batch: gfx::batch::CoreBatch<P>,
    params: P,
    slice: gfx::Slice<P::Resources>,
    depth: S,
}

impl<S: PartialOrd, P: gfx::shade::ShaderParam> Object<S, P> {
    fn cmp_depth(&self, other: &Object<S, P>) -> Ordering {
        self.depth.partial_cmp(&other.depth)
            .unwrap_or(Ordering::Equal)
    }
}

pub enum Sort {
    FrontToBack,
    BackToFront,
    Program,
    Mesh,
    DrawState,
}

pub trait ToDepth {
    type Depth: PartialOrd;
    fn to_depth(&self) -> Self::Depth;
}

/// Phase is doing draw call accumulating and sorting,
/// based a given technique.
pub struct Phase<
    R: gfx::Resources,
    M: ::Material,
    Z: ToDepth,
    T: ::Technique<R, M, Z>,
>{
    pub name: String,
    technique: T,
    sort: Vec<Sort>,
    queue: draw_queue::Queue<Object<Z::Depth, T::Params>>,
}

impl<
    R: gfx::Resources,
    M: ::Material,
    Z: ToDepth,
    T: ::Technique<R, M, Z>,
> Phase<R, M, Z, T> {
    pub fn new(name: &str, tech: T, sort: Sort) -> Phase<R, M, Z, T> {
        Phase {
            name: name.to_string(),
            technique: tech,
            sort: vec![sort],
            queue: draw_queue::Queue::new(),
        }
    }
}

impl<
    D: gfx::Device,
    M: ::Material,
    Z: ToDepth + Copy,
    E: ::Entity<D::Resources, M>,
    T: ::Technique<D::Resources, M, Z>,
>AbstractPhase<D, E, Z> for Phase<D::Resources, M, Z, T> {
    fn does_apply(&self, entity: &E) -> bool {
        self.technique.does_apply(entity.get_mesh().0, entity.get_material())
    }

    fn enqueue(&mut self, entity: &E, data: Z,
               context: &mut gfx::batch::Context<D::Resources>)
               -> Result<(), gfx::batch::Error> {
        // unable to use `self.does_apply` here
        debug_assert!(self.technique.does_apply(
            entity.get_mesh().0, entity.get_material()
        ));
        let depth = data.to_depth();
        // TODO: batch cache
        let (orig_mesh, slice) = entity.get_mesh();
        let (program, mut params, inst_mesh, state) = self.technique.compile(
            orig_mesh, entity.get_material(), data);
        let batch_result = match inst_mesh {
            Some(m) => {
                let mesh = &gfx::Mesh {
                    num_vertices: orig_mesh.num_vertices,
                    attributes: orig_mesh.attributes.iter()
                        .chain(m.attributes.iter()).
                        map(|a| a.clone()).collect(),
                };
                context.make_core(program, mesh, state)
            },
            None => {
                context.make_core(program, orig_mesh, state)
            },
        };
        match batch_result {
            Ok(b) => {
                //TODO: only if cached
                self.technique.fix_params(entity.get_material(),
                                          &data, &mut params);
                let object = Object {
                    batch: b,
                    params: params,
                    slice: slice.clone(),
                    depth: depth,
                };
                self.queue.objects.push(object);
                Ok(())
            },
            Err(e) => Err(e),
        }
    }

    fn flush(&mut self, frame: &gfx::Frame<D::Resources>,
             context: &gfx::batch::Context<D::Resources>,
             renderer: &mut gfx::Renderer<D::Resources, D::CommandBuffer>)
             -> Result<(), FlushError> {
        // sort the queue
        match self.sort.first() {
            Some(&Sort::FrontToBack) =>
                self.queue.sort(|a, b| a.cmp_depth(&b)),
            Some(&Sort::BackToFront) =>
                self.queue.sort(|a, b| b.cmp_depth(&a)),
            Some(&Sort::Program) =>
                self.queue.sort(|a, b| a.batch.cmp_program(&b.batch)),
            Some(&Sort::Mesh) =>
                self.queue.sort(|a, b| a.batch.cmp_mesh(&b.batch)),
            Some(&Sort::DrawState) =>
                self.queue.sort(|a, b| a.batch.cmp_state(&b.batch)),
            None => (),
        }
        // call the draws
        for o in self.queue.iter() {
            match renderer.draw(&context.bind(&o.batch, &o.slice, &o.params), frame) {
                Ok(_) => (),
                e => return e,
            }
        }
        // done
        self.queue.objects.clear();
        Ok(())
    }
}
<commit_msg>Refactored instancing meshes<commit_after>extern crate draw_queue;

use std::cmp::Ordering;
use gfx;

pub type FlushError = gfx::DrawError<gfx::batch::OutOfBounds>;

pub trait AbstractPhase<D: gfx::Device, E, Z> {
    /// Check if it makes sense to draw this entity
    fn does_apply(&self, &E) -> bool;
    /// Add an entity to the queue
    fn enqueue(&mut self, &E, Z, &mut gfx::batch::Context<D::Resources>)
               -> Result<(), gfx::batch::Error>;
    /// Flush the queue into a given renderer
    fn flush(&mut self, &gfx::Frame<D::Resources>,
             &gfx::batch::Context<D::Resources>,
             &mut gfx::Renderer<D::Resources, D::CommandBuffer>)
             -> Result<(), FlushError>;
}

struct Object<S, P: gfx::shade::ShaderParam> {
    batch: gfx::batch::CoreBatch<P>,
    params: P,
    slice: gfx::Slice<P::Resources>,
    depth: S,
}

impl<S: PartialOrd, P: gfx::shade::ShaderParam> Object<S, P> {
    fn cmp_depth(&self, other: &Object<S, P>) -> Ordering {
        self.depth.partial_cmp(&other.depth)
            .unwrap_or(Ordering::Equal)
    }
}

pub enum Sort {
    FrontToBack,
    BackToFront,
    Program,
    Mesh,
    DrawState,
}

pub trait ToDepth {
    type Depth: PartialOrd;
    fn to_depth(&self) -> Self::Depth;
}

/// Phase is doing draw call accumulating and sorting,
/// based a given technique.
pub struct Phase<
    R: gfx::Resources,
    M: ::Material,
    Z: ToDepth,
    T: ::Technique<R, M, Z>,
>{
    pub name: String,
    technique: T,
    sort: Vec<Sort>,
    queue: draw_queue::Queue<Object<Z::Depth, T::Params>>,
}

impl<
    R: gfx::Resources,
    M: ::Material,
    Z: ToDepth,
    T: ::Technique<R, M, Z>,
> Phase<R, M, Z, T> {
    pub fn new(name: &str, tech: T, sort: Sort) -> Phase<R, M, Z, T> {
        Phase {
            name: name.to_string(),
            technique: tech,
            sort: vec![sort],
            queue: draw_queue::Queue::new(),
        }
    }
}

impl<
    D: gfx::Device,
    M: ::Material,
    Z: ToDepth + Copy,
    E: ::Entity<D::Resources, M>,
    T: ::Technique<D::Resources, M, Z>,
>AbstractPhase<D, E, Z> for Phase<D::Resources, M, Z, T> {
    fn does_apply(&self, entity: &E) -> bool {
        self.technique.does_apply(entity.get_mesh().0, entity.get_material())
    }

    fn enqueue(&mut self, entity: &E, data: Z,
               context: &mut gfx::batch::Context<D::Resources>)
               -> Result<(), gfx::batch::Error> {
        // unable to use `self.does_apply` here
        debug_assert!(self.technique.does_apply(
            entity.get_mesh().0, entity.get_material()
        ));
        let depth = data.to_depth();
        // TODO: batch cache
        let (orig_mesh, slice) = entity.get_mesh();
        let (program, mut params, inst_mesh, state) = self.technique.compile(
            orig_mesh, entity.get_material(), data);
        let mut temp_mesh = gfx::Mesh::new(orig_mesh.num_vertices);
        let mesh = match inst_mesh {
            Some(m) => {
                temp_mesh.attributes.extend(orig_mesh.attributes.iter()
                        .chain(m.attributes.iter()).map(|a| a.clone()));
                &temp_mesh
            },
            None => orig_mesh,
        };
        match context.make_core(program, mesh, state) {
            Ok(b) => {
                //TODO: only if cached
                self.technique.fix_params(entity.get_material(),
                                          &data, &mut params);
                let object = Object {
                    batch: b,
                    params: params,
                    slice: slice.clone(),
                    depth: depth,
                };
                self.queue.objects.push(object);
                Ok(())
            },
            Err(e) => Err(e),
        }
    }

    fn flush(&mut self, frame: &gfx::Frame<D::Resources>,
             context: &gfx::batch::Context<D::Resources>,
             renderer: &mut gfx::Renderer<D::Resources, D::CommandBuffer>)
             -> Result<(), FlushError> {
        // sort the queue
        match self.sort.first() {
            Some(&Sort::FrontToBack) =>
                self.queue.sort(|a, b| a.cmp_depth(&b)),
            Some(&Sort::BackToFront) =>
                self.queue.sort(|a, b| b.cmp_depth(&a)),
            Some(&Sort::Program) =>
                self.queue.sort(|a, b| a.batch.cmp_program(&b.batch)),
            Some(&Sort::Mesh) =>
                self.queue.sort(|a, b| a.batch.cmp_mesh(&b.batch)),
            Some(&Sort::DrawState) =>
                self.queue.sort(|a, b| a.batch.cmp_state(&b.batch)),
            None => (),
        }
        // call the draws
        for o in self.queue.iter() {
            match renderer.draw(&context.bind(&o.batch, &o.slice, &o.params), frame) {
                Ok(_) => (),
                e => return e,
            }
        }
        // done
        self.queue.objects.clear();
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate htmlescape;
extern crate regex;

use irc::client::prelude::*;

use self::regex::Regex;

use plugin::*;
use utils;

use self::error::*;
use error::FrippyError;
use error::ErrorKind as FrippyErrorKind;
use failure::Fail;
use failure::ResultExt;

lazy_static! {
    static ref RE: Regex = Regex::new(r"(^|\s)(https?://\S+)").unwrap();
}

#[derive(PluginName, Debug)]
pub struct Url {
    max_kib: usize,
}

impl Url {
    /// If a file is larger than `max_kib` KiB the download is stopped
    pub fn new(max_kib: usize) -> Url {
        Url { max_kib: max_kib }
    }

    fn grep_url(&self, msg: &str) -> Option<String> {
        let captures = RE.captures(msg)?;
        debug!("Url captures: {:?}", captures);

        Some(captures.get(2)?.as_str().to_owned())
    }

    fn get_title<'a>(&self, body: &str) -> Result<String, UrlError> {
        let title = body.find("<title>")
            .map(|start| body.find("</title>").map(|end| &body[start + 7..end]))
            .and_then(|s| s).ok_or(ErrorKind::MissingTitle)?;

        debug!("Title: {:?}", title);

        htmlescape::decode_html(title).map_err(|_| ErrorKind::HtmlDecoding.into())
    }

    fn url(&self, text: &str) -> Result<String, UrlError> {
        let url = self.grep_url(text).ok_or(ErrorKind::MissingUrl)?;
        let body = utils::download(&url, Some(self.max_kib)).context(ErrorKind::Download)?;

        let title = self.get_title(&body)?;

        Ok(title.replace('\n', "|").replace('\r', "|"))
    }
}

impl Plugin for Url {
    fn execute(&self, _: &IrcClient, message: &Message) -> ExecutionStatus {
        match message.command {
            Command::PRIVMSG(_, ref msg) => if RE.is_match(msg) {
                ExecutionStatus::RequiresThread
            } else {
                ExecutionStatus::Done
            },
            _ => ExecutionStatus::Done,
        }
    }

    fn execute_threaded(&self, client: &IrcClient, message: &Message) -> Result<(), FrippyError> {
        Ok(match message.command {
            Command::PRIVMSG(_, ref content) => match self.url(content) {
                Ok(title) => client
                    .send_privmsg(message.response_target().unwrap(), &title)
                    .context(FrippyErrorKind::Connection)?,
                Err(e) => Err(e).context(FrippyErrorKind::Url)?,
            },
            _ => (),
        })
    }

    fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> {
        Ok(client
            .send_notice(
                &command.source,
                "This Plugin does not implement any commands.",
            )
            .context(FrippyErrorKind::Connection)?)
    }

    fn evaluate(&self, _: &IrcClient, command: PluginCommand) -> Result<String, String> {
        self.url(&command.tokens[0])
            .map_err(|e| e.cause().unwrap().to_string())
    }
}

pub mod error {
    /// A URL plugin error
    #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
    #[error = "UrlError"]
    pub enum ErrorKind {
        /// A download error
        #[fail(display = "A download error occured")]
        Download,

        /// Missing URL error
        #[fail(display = "No URL was found")]
        MissingUrl,

        /// Missing title error
        #[fail(display = "No title was found")]
        MissingTitle,

        /// Html decoding error
        #[fail(display = "Failed to decode Html characters")]
        HtmlDecoding,
    }
}
<commit_msg>Consider title tags with attributes<commit_after>extern crate htmlescape;
extern crate regex;

use irc::client::prelude::*;

use self::regex::Regex;

use plugin::*;
use utils;

use self::error::*;
use error::FrippyError;
use error::ErrorKind as FrippyErrorKind;
use failure::Fail;
use failure::ResultExt;

lazy_static! {
    static ref RE: Regex = Regex::new(r"(^|\s)(https?://\S+)").unwrap();
}

#[derive(PluginName, Debug)]
pub struct Url {
    max_kib: usize,
}

impl Url {
    /// If a file is larger than `max_kib` KiB the download is stopped
    pub fn new(max_kib: usize) -> Url {
        Url { max_kib: max_kib }
    }

    fn grep_url(&self, msg: &str) -> Option<String> {
        let captures = RE.captures(msg)?;
        debug!("Url captures: {:?}", captures);

        Some(captures.get(2)?.as_str().to_owned())
    }

    fn get_title<'a>(&self, body: &str) -> Result<String, UrlError> {
        let title = body.find("<title")
            .map(|tag| {
                body[tag..]
                    .find('>')
                    .map(|offset| tag + offset + 1)
                    .map(|start| {
                        body[start..]
                            .find("</title>")
                            .map(|offset| start + offset)
                            .map(|end| &body[start..end])
                    })
            })
            .and_then(|s| s.and_then(|s| s))
            .ok_or(ErrorKind::MissingTitle)?;

        debug!("Title: {:?}", title);

        htmlescape::decode_html(title).map_err(|_| ErrorKind::HtmlDecoding.into())
    }

    fn url(&self, text: &str) -> Result<String, UrlError> {
        let url = self.grep_url(text).ok_or(ErrorKind::MissingUrl)?;
        let body = utils::download(&url, Some(self.max_kib)).context(ErrorKind::Download)?;

        let title = self.get_title(&body)?;

        Ok(title.replace('\n', "|").replace('\r', "|"))
    }
}

impl Plugin for Url {
    fn execute(&self, _: &IrcClient, message: &Message) -> ExecutionStatus {
        match message.command {
            Command::PRIVMSG(_, ref msg) => if RE.is_match(msg) {
                ExecutionStatus::RequiresThread
            } else {
                ExecutionStatus::Done
            },
            _ => ExecutionStatus::Done,
        }
    }

    fn execute_threaded(&self, client: &IrcClient, message: &Message) -> Result<(), FrippyError> {
        Ok(match message.command {
            Command::PRIVMSG(_, ref content) => match self.url(content) {
                Ok(title) => client
                    .send_privmsg(message.response_target().unwrap(), &title)
                    .context(FrippyErrorKind::Connection)?,
                Err(e) => Err(e).context(FrippyErrorKind::Url)?,
            },
            _ => (),
        })
    }

    fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> {
        Ok(client
            .send_notice(
                &command.source,
                "This Plugin does not implement any commands.",
            )
            .context(FrippyErrorKind::Connection)?)
    }

    fn evaluate(&self, _: &IrcClient, command: PluginCommand) -> Result<String, String> {
        self.url(&command.tokens[0])
            .map_err(|e| e.cause().unwrap().to_string())
    }
}

pub mod error {
    /// A URL plugin error
    #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
    #[error = "UrlError"]
    pub enum ErrorKind {
        /// A download error
        #[fail(display = "A download error occured")]
        Download,

        /// Missing URL error
        #[fail(display = "No URL was found")]
        MissingUrl,

        /// Missing title error
        #[fail(display = "No title was found")]
        MissingTitle,

        /// Html decoding error
        #[fail(display = "Failed to decode Html characters")]
        HtmlDecoding,
    }
}
<|endoftext|>


<commit_before>//! A PNG Encoder
//!
//! This implementation uses the ```flate``` crate for compression
//! and selects the filter type using the sum of absolute differences method.
//!
//! For each row the filter method that produces the lowest integer when its bytes
//! are interpreted as signed numbers and summed is chosen as the filter.

use std::slice;
use std::old_io:: {
    IoResult,
    MemWriter
};
use std::num::FromPrimitive;
use std::iter::repeat;

use color;
use super::hash::Crc32;

use super::filter::filter;
use super::decoder::PNGSIGNATURE;

/// The representation of a PNG encoder
pub struct PNGEncoder<'a, W: 'a> {
    w: &'a mut W,
    crc: Crc32
}

impl<'a, W: Writer> PNGEncoder<'a, W> {
    /// Create a new encoder that writes its output to ```w```
    pub fn new(w: &mut W) -> PNGEncoder<W> {
        PNGEncoder {
            w: w,
            crc: Crc32::new()
        }
    }

    /// Encodes the image ```image```
    /// that has dimensions ```width``` and ```height```
    /// and ```ColorType``` ```c```
    pub fn encode(&mut self,
                  image: &[u8],
                  width: u32,
                  height: u32,
                  c: color::ColorType) -> IoResult<()> {

        let _ = try!(self.write_signature());
        let (bytes, bpp) = build_ihdr(width, height, c);

        let _ = try!(self.write_chunk("IHDR", &bytes));
        let compressed_bytes = build_idat(image, bpp, width, height);

        for chunk in compressed_bytes.chunks(1024 * 256) {
            let _ = try!(self.write_chunk("IDAT", chunk));
        }

        self.write_chunk("IEND", &[])
    }

    fn write_signature(&mut self) -> IoResult<()> {
        self.w.write_all(&PNGSIGNATURE)
    }

    fn write_chunk(&mut self, name: &str, buf: &[u8]) -> IoResult<()> {
        self.crc.reset();
        self.crc.update(name);
        self.crc.update(&buf);

        let crc = self.crc.checksum();

        let _ = try!(self.w.write_be_u32(buf.len() as u32));
        let _ = try!(self.w.write_str(name));
        let _ = try!(self.w.write_all(buf));
        let _ = try!(self.w.write_be_u32(crc));

        Ok(())
    }
}

fn build_ihdr(width: u32, height: u32, c: color::ColorType) -> (Vec<u8>, usize) {
    let mut m = MemWriter::with_capacity(13);

    let _ = m.write_be_u32(width);
    let _ = m.write_be_u32(height);

    let (colortype, bit_depth) = match c {
        color::ColorType::Gray(1)    => (0, 1),
        color::ColorType::Gray(2)    => (0, 2),
        color::ColorType::Gray(4)    => (0, 4),
        color::ColorType::Gray(8)    => (0, 8),
        color::ColorType::Gray(16)   => (0, 16),
        color::ColorType::RGB(8)     => (2, 8),
        color::ColorType::RGB(16)    => (2, 16),
        color::ColorType::Palette(1) => (3, 1),
        color::ColorType::Palette(2) => (3, 2),
        color::ColorType::Palette(4) => (3, 4),
        color::ColorType::Palette(8) => (3, 8),
        color::ColorType::GrayA(8)   => (4, 8),
        color::ColorType::GrayA(16)  => (4, 16),
        color::ColorType::RGBA(8)    => (6, 8),
        color::ColorType::RGBA(16)   => (6, 16),
        _ => panic!("unsupported color type and bitdepth")
    };

    let _ = m.write_u8(bit_depth);
    let _ = m.write_u8(colortype);

    // Compression method, filter method and interlace
    let _ = m.write_u8(0);
    let _ = m.write_u8(0);
    let _ = m.write_u8(0);

    let channels = match colortype {
        0 => 1,
        2 => 3,
        3 => 3,
        4 => 2,
        6 => 4,
        _ => panic!("unknown colour type")
    };

    let bpp = ((channels * bit_depth + 7) / 8) as usize;

    (m.into_inner(), bpp)
}

fn sum_abs_difference(buf: &[u8]) -> i32 {
    buf.iter().fold(0i32, | sum, &b | sum + if b < 128 {b as i32} else {256 - b as i32})
}

fn select_filter(rowlength: usize, bpp: usize, previous: &[u8], current_s: &mut [u8]) -> u8 {
    let mut sum    = sum_abs_difference(&current_s[..rowlength]);
    let mut method = 0;

    for (i, current) in current_s.chunks_mut(rowlength).enumerate() {
        filter(FromPrimitive::from_u8(i as u8 + 1).unwrap(), bpp, previous, current);

        let this_sum = sum_abs_difference(current);

        if this_sum < sum {
            sum = this_sum;
            method = i as u8 + 1;
        }
    }

    method
}

fn build_idat(image: &[u8], bpp: usize, width: u32, height: u32) -> Vec<u8> {
    use flate::deflate_bytes_zlib;

    let rowlen = bpp * width as usize;

    let mut p: Vec<u8> = repeat(0u8).take(rowlen).collect();
    let mut c: Vec<u8> = repeat(0u8).take(4 * rowlen).collect();
    let mut b: Vec<u8> = repeat(0u8).take(height as usize + rowlen * height as usize).collect();

    for (row, outrow) in image.chunks(rowlen).zip(b.chunks_mut(1 + rowlen)) {
        for s in c.chunks_mut(rowlen) {
            slice::bytes::copy_memory(s, row);
        }

        let filter = select_filter(rowlen, bpp, &p, &mut c);

        outrow[0]  = filter;
        let out    = &mut outrow[1..];

        match filter {
            0 => slice::bytes::copy_memory(out, row),
            _ => {
                let stride = (filter as usize - 1) * rowlen;
                slice::bytes::copy_memory(out, &c[stride..stride + rowlen])
            }
        }

        slice::bytes::copy_memory(&mut p, row);
    }

    deflate_bytes_zlib(&b).unwrap().to_vec()
}
<commit_msg>Update for latest Rust<commit_after>//! A PNG Encoder
//!
//! This implementation uses the ```flate``` crate for compression
//! and selects the filter type using the sum of absolute differences method.
//!
//! For each row the filter method that produces the lowest integer when its bytes
//! are interpreted as signed numbers and summed is chosen as the filter.

use std::slice;
use std::old_io:: {
    IoResult,
    MemWriter
};
use std::num::FromPrimitive;
use std::iter::repeat;

use color;
use super::hash::Crc32;

use super::filter::filter;
use super::decoder::PNGSIGNATURE;

/// The representation of a PNG encoder
pub struct PNGEncoder<'a, W: 'a> {
    w: &'a mut W,
    crc: Crc32
}

impl<'a, W: Writer> PNGEncoder<'a, W> {
    /// Create a new encoder that writes its output to ```w```
    pub fn new(w: &mut W) -> PNGEncoder<W> {
        PNGEncoder {
            w: w,
            crc: Crc32::new()
        }
    }

    /// Encodes the image ```image```
    /// that has dimensions ```width``` and ```height```
    /// and ```ColorType``` ```c```
    pub fn encode(&mut self,
                  image: &[u8],
                  width: u32,
                  height: u32,
                  c: color::ColorType) -> IoResult<()> {

        let _ = try!(self.write_signature());
        let (bytes, bpp) = build_ihdr(width, height, c);

        let _ = try!(self.write_chunk("IHDR", &bytes));
        let compressed_bytes = build_idat(image, bpp, width, height);

        for chunk in compressed_bytes.chunks(1024 * 256) {
            let _ = try!(self.write_chunk("IDAT", chunk));
        }

        self.write_chunk("IEND", &[])
    }

    fn write_signature(&mut self) -> IoResult<()> {
        self.w.write_all(&PNGSIGNATURE)
    }

    fn write_chunk(&mut self, name: &str, buf: &[u8]) -> IoResult<()> {
        self.crc.reset();
        self.crc.update(name);
        self.crc.update(&buf);

        let crc = self.crc.checksum();

        let _ = try!(self.w.write_be_u32(buf.len() as u32));
        let _ = try!(self.w.write_str(name));
        let _ = try!(self.w.write_all(buf));
        let _ = try!(self.w.write_be_u32(crc));

        Ok(())
    }
}

fn build_ihdr(width: u32, height: u32, c: color::ColorType) -> (Vec<u8>, usize) {
    let mut m = MemWriter::with_capacity(13);

    let _ = m.write_be_u32(width);
    let _ = m.write_be_u32(height);

    let (colortype, bit_depth) = match c {
        color::ColorType::Gray(1)    => (0, 1),
        color::ColorType::Gray(2)    => (0, 2),
        color::ColorType::Gray(4)    => (0, 4),
        color::ColorType::Gray(8)    => (0, 8),
        color::ColorType::Gray(16)   => (0, 16),
        color::ColorType::RGB(8)     => (2, 8),
        color::ColorType::RGB(16)    => (2, 16),
        color::ColorType::Palette(1) => (3, 1),
        color::ColorType::Palette(2) => (3, 2),
        color::ColorType::Palette(4) => (3, 4),
        color::ColorType::Palette(8) => (3, 8),
        color::ColorType::GrayA(8)   => (4, 8),
        color::ColorType::GrayA(16)  => (4, 16),
        color::ColorType::RGBA(8)    => (6, 8),
        color::ColorType::RGBA(16)   => (6, 16),
        _ => panic!("unsupported color type and bitdepth")
    };

    let _ = m.write_u8(bit_depth);
    let _ = m.write_u8(colortype);

    // Compression method, filter method and interlace
    let _ = m.write_u8(0);
    let _ = m.write_u8(0);
    let _ = m.write_u8(0);

    let channels = match colortype {
        0 => 1,
        2 => 3,
        3 => 3,
        4 => 2,
        6 => 4,
        _ => panic!("unknown colour type")
    };

    let bpp = ((channels * bit_depth + 7) / 8) as usize;

    (m.into_inner(), bpp)
}

fn sum_abs_difference(buf: &[u8]) -> i32 {
    buf.iter().fold(0i32, | sum, &b | sum + if b < 128 {b as i32} else {256 - b as i32})
}

fn select_filter(rowlength: usize, bpp: usize, previous: &[u8], current_s: &mut [u8]) -> u8 {
    let mut sum    = sum_abs_difference(&current_s[..rowlength]);
    let mut method = 0;

    for (i, current) in current_s.chunks_mut(rowlength).enumerate() {
        filter(FromPrimitive::from_u8(i as u8 + 1).unwrap(), bpp, previous, current);

        let this_sum = sum_abs_difference(current);

        if this_sum < sum {
            sum = this_sum;
            method = i as u8 + 1;
        }
    }

    method
}

fn build_idat(image: &[u8], bpp: usize, width: u32, height: u32) -> Vec<u8> {
    use flate::deflate_bytes_zlib;

    let rowlen = bpp * width as usize;

    let mut p: Vec<u8> = repeat(0u8).take(rowlen).collect();
    let mut c: Vec<u8> = repeat(0u8).take(4 * rowlen).collect();
    let mut b: Vec<u8> = repeat(0u8).take(height as usize + rowlen * height as usize).collect();

    for (row, outrow) in image.chunks(rowlen).zip(b.chunks_mut(1 + rowlen)) {
        for s in c.chunks_mut(rowlen) {
            slice::bytes::copy_memory(s, row);
        }

        let filter = select_filter(rowlen, bpp, &p, &mut c);

        outrow[0]  = filter;
        let out    = &mut outrow[1..];

        match filter {
            0 => slice::bytes::copy_memory(out, row),
            _ => {
                let stride = (filter as usize - 1) * rowlen;
                slice::bytes::copy_memory(out, &c[stride..stride + rowlen])
            }
        }

        slice::bytes::copy_memory(&mut p, row);
    }

    deflate_bytes_zlib(&b).to_vec()
}
<|endoftext|>


<commit_before>use mojom_syntax::Error as SyntaxError;
use mojom_syntax::{Module, MojomFile};

#[derive(Debug)]
pub(crate) enum Error {
    SyntaxError(SyntaxError),
}

impl From<SyntaxError> for Error {
    fn from(err: SyntaxError) -> Error {
        Error::SyntaxError(err)
    }
}

pub(crate) struct Analysis {
    pub(crate) module: Option<Module>,
    pub(crate) diagnostics: Vec<lsp_types::Diagnostic>,
}

fn partial_text<'a>(text: &'a str, range: &mojom_syntax::Range) -> &'a str {
    &text[range.start..range.end]
}

fn is_keyword(ident: &str) -> bool {
    ident == "array"
        || ident == "true"
        || ident == "false"
        || ident == "default"
        || ident == "bool"
        || ident == "int8"
        || ident == "uint8"
        || ident == "int16"
        || ident == "uint8"
        || ident == "int32"
        || ident == "uint32"
        || ident == "int64"
        || ident == "uint64"
        || ident == "float"
        || ident == "double"
        || ident == "associated"
        || ident == "const"
        || ident == "enum"
        || ident == "handle"
        || ident == "import"
        || ident == "interface"
        || ident == "map"
        || ident == "module"
        || ident == "struct"
        || ident == "union"
}

fn create_diagnostic(
    text: &str,
    range: &mojom_syntax::Range,
    message: String,
) -> lsp_types::Diagnostic {
    let start = mojom_syntax::line_col(text, range.start).unwrap();
    let end = mojom_syntax::line_col(text, range.end).unwrap();
    let range = crate::diagnostic::into_lsp_range(&start, &end);
    lsp_types::Diagnostic {
        range: range,
        severity: Some(lsp_types::DiagnosticSeverity::Error),
        code: Some(lsp_types::NumberOrString::String("mojom".to_owned())),
        source: Some("mojom-lsp".to_owned()),
        message: message,
        related_information: None,
    }
}

fn check_invalid_keywords(
    text: &str,
    mojom: &MojomFile,
    diagnostics: &mut Vec<lsp_types::Diagnostic>,
) {
    let idents = mojom_syntax::preorder(mojom).filter_map(|traverse| match traverse {
        mojom_syntax::Traversal::EnterInterface(stmt) => Some(&stmt.name),
        mojom_syntax::Traversal::EnterStruct(stmt) => Some(&stmt.name),
        mojom_syntax::Traversal::Module(stmt) => Some(&stmt.name),
        mojom_syntax::Traversal::Method(stmt) => Some(&stmt.name),
        mojom_syntax::Traversal::Union(stmt) => Some(&stmt.name),
        mojom_syntax::Traversal::Enum(stmt) => Some(&stmt.name),
        mojom_syntax::Traversal::Const(stmt) => Some(&stmt.name),
        mojom_syntax::Traversal::StructField(stmt) => Some(&stmt.name),
        _ => None,
    });
    for range in idents {
        let name = partial_text(&text, range);
        if is_keyword(name) {
            let message = format!("Unexpected keyword: {}", name);
            let diagnostic = create_diagnostic(&text, range, message);
            diagnostics.push(diagnostic);
        }
    }
}

fn find_module(
    text: &str,
    mojom: &MojomFile,
    diagnostics: &mut Vec<lsp_types::Diagnostic>,
) -> Option<Module> {
    let mut module: Option<Module> = None;
    for stmt in &mojom.stmts {
        match stmt {
            mojom_syntax::Statement::Module(stmt) => {
                if let Some(ref module) = module {
                    let message = format!(
                        "Found more than one module statement: {} and {}",
                        partial_text(&text, &module.name),
                        partial_text(&text, &stmt.name)
                    );
                    let diagnostic = create_diagnostic(&text, &stmt.name, message);
                    diagnostics.push(diagnostic);
                } else {
                    module = Some(stmt.clone());
                }
            }
            _ => (),
        }
    }
    module
}

pub(crate) fn check_semantics(text: &str, mojom: &MojomFile) -> Analysis {
    let mut diagnostics = Vec::new();
    let module = find_module(text, mojom, &mut diagnostics);

    check_invalid_keywords(text, mojom, &mut diagnostics);

    Analysis {
        module: module,
        diagnostics: diagnostics,
    }
}
<commit_msg>Remove check_invalid_keyword()<commit_after>use mojom_syntax::Error as SyntaxError;
use mojom_syntax::{Module, MojomFile};

#[derive(Debug)]
pub(crate) enum Error {
    SyntaxError(SyntaxError),
}

impl From<SyntaxError> for Error {
    fn from(err: SyntaxError) -> Error {
        Error::SyntaxError(err)
    }
}

pub(crate) struct Analysis {
    pub(crate) module: Option<Module>,
    pub(crate) diagnostics: Vec<lsp_types::Diagnostic>,
}

fn partial_text<'a>(text: &'a str, range: &mojom_syntax::Range) -> &'a str {
    &text[range.start..range.end]
}

fn create_diagnostic(
    text: &str,
    range: &mojom_syntax::Range,
    message: String,
) -> lsp_types::Diagnostic {
    let start = mojom_syntax::line_col(text, range.start).unwrap();
    let end = mojom_syntax::line_col(text, range.end).unwrap();
    let range = crate::diagnostic::into_lsp_range(&start, &end);
    lsp_types::Diagnostic {
        range: range,
        severity: Some(lsp_types::DiagnosticSeverity::Error),
        code: Some(lsp_types::NumberOrString::String("mojom".to_owned())),
        source: Some("mojom-lsp".to_owned()),
        message: message,
        related_information: None,
    }
}

fn find_module(
    text: &str,
    mojom: &MojomFile,
    diagnostics: &mut Vec<lsp_types::Diagnostic>,
) -> Option<Module> {
    let mut module: Option<Module> = None;
    for stmt in &mojom.stmts {
        match stmt {
            mojom_syntax::Statement::Module(stmt) => {
                if let Some(ref module) = module {
                    let message = format!(
                        "Found more than one module statement: {} and {}",
                        partial_text(&text, &module.name),
                        partial_text(&text, &stmt.name)
                    );
                    let diagnostic = create_diagnostic(&text, &stmt.name, message);
                    diagnostics.push(diagnostic);
                } else {
                    module = Some(stmt.clone());
                }
            }
            _ => (),
        }
    }
    module
}

pub(crate) fn check_semantics(text: &str, mojom: &MojomFile) -> Analysis {
    let mut diagnostics = Vec::new();
    let module = find_module(text, mojom, &mut diagnostics);
    Analysis {
        module: module,
        diagnostics: diagnostics,
    }
}
<|endoftext|>


<commit_before>//
// rslex - a lexer generator for rust
//
// regexp.rs
// Regexp parsing and representation
//
// Andrei de A. Formiga, 2013-08-09
//

extern mod std;

use buffer::LookaheadBuffer;
//use parser::skip_whitespace;

#[deriving(Eq)]
enum Token { LBrack, RBrack, Id(~str), LParen, RParen, Asterisk,
             Plus, Bar, Dash, String(~str), Eof }

enum Ast { Symb(~str), Str(~str), Union(~Ast, ~Ast),
           Conc(~Ast, ~Ast), Star(~Ast), OnePlus(~Ast),
           CharClass(char, char), Epsilon }

fn parse_string(buffer: &mut LookaheadBuffer, delim: char) -> ~str {
    let mut res : ~str = ~"";
    let mut c = buffer.next_char();
    while c != Some(delim) {
        if (c.is_none()) {
            fail!("Unexpected end of file. Expected closing {}", delim);
        }
        res.push_char(c.unwrap());
        c = buffer.next_char();
    }
    res
}

#[test]
fn test_parse_string() {
    let mut b1 = LookaheadBuffer::new("abc'* ");
    assert_eq!(parse_string(&mut b1, '\''), ~"abc");
    assert_eq!(b1.next_char(), Some('*'));

    let mut b2 = LookaheadBuffer::new("abc'def\"  ");
    assert_eq!(parse_string(&mut b2, '"'), ~"abc'def");
    assert_eq!(b2.next_char(), Some(' '));
}

#[test]
#[should_fail]
fn unclosed_string() {
    let mut b1 = LookaheadBuffer::new("abc'def  ");
    assert_eq!(parse_string(&mut b1, '"'), ~"abc'def");
}

// #[inline]
// fn is_id_char(c: char) -> bool {
//     std::char::is_alphanumeric(c) || c == '_'
// }

// fn parse_id(buffer: &mut LookaheadBuffer, first: char) -> ~str {
//     let mut res : ~str = ~"";
//     res.push_char(first);
//     let mut c = buffer.next_char();
//     while is_id_char(c) {
//         res.push_char(c);
//         c = buffer.next_char();
//     }
//     buffer.return_char(c);
//     res
// }

// #[test]
// fn test_parse_id() {
//     let mut b1 = LookaheadBuffer::new("abc'* ");
//     assert!(std::str::eq(&parse_id(&mut b1, 'x'), &~"xabc"));
//     assert!(b1.next_char() == '\'');

//     let mut b2 = LookaheadBuffer::new("bc_def   ");
//     assert!(std::str::eq(&parse_id(&mut b2, 'a'), &~"abc_def"));

//     let mut b3 = LookaheadBuffer::new("_times|'xy')*   ");
//     assert!(std::str::eq(&parse_id(&mut b3, 'n'), &~"n_times"));
//     assert!(b3.next_char() == '|');

//     let mut b4 = LookaheadBuffer::new(" +xy)*   ");
//     assert!(std::str::eq(&parse_id(&mut b4, 'n'), &~"n"));
//     assert!(b4.next_char() == ' ');
//     assert!(b4.next_char() == '+');
//     assert!(b4.next_char() == 'x');
//     assert!(std::str::eq(&parse_id(&mut b4, 'x'), &~"xy"));
// }

// #[inline]
// fn match_next_token(buffer: &mut LookaheadBuffer, t: ~Token) {
//     let rt = get_next_token(buffer);
//     if rt != t {
//         fail!("Unexpeced token: expected {:?}, got {:?}", t, rt);
//     }
// }

// fn get_next_token(buffer: &mut LookaheadBuffer) -> ~Token {
//     skip_whitespace(buffer);
//     match buffer.next_char() {
//         '[' => ~LBrack,
//         ']' => ~RBrack,
//         '(' => ~LParen,
//         ')' => ~RParen,
//         '*' => ~Asterisk,
//         '+' => ~Plus,
//         '|' => ~Bar,
//         '-' => ~Dash,
//         '\'' => ~String(parse_string(buffer, '\'')),
//         '"' => ~String(parse_string(buffer, '"')),
//         c if std::char::is_alphabetic(c) => ~Id(parse_id(buffer, c)),
//         c if is_eof(c) => ~Eof,
//         c => fail!("Unexpected character: {}", c)
//     }
// }

// #[test]
// fn test_get_next_token() {
//     let mut b1 = LookaheadBuffer::new("'return'");
//     assert!(get_next_token(&mut b1) == ~String(~"return"));

//     let mut b2 = LookaheadBuffer::new("return");
//     assert!(get_next_token(&mut b2) == ~Id(~"return"));

//     let mut b3 = LookaheadBuffer::new("(['a'-'z'])(['A'-'Z'])*");
//     assert!(get_next_token(&mut b3) == ~LParen);
//     assert!(get_next_token(&mut b3) == ~LBrack);
//     assert!(get_next_token(&mut b3) == ~String(~"a"));
//     assert!(get_next_token(&mut b3) == ~Dash);
//     assert!(get_next_token(&mut b3) == ~String(~"z"));
//     assert!(get_next_token(&mut b3) == ~RBrack);
//     assert!(get_next_token(&mut b3) == ~RParen);
//     assert!(get_next_token(&mut b3) == ~LParen);
//     assert!(get_next_token(&mut b3) == ~LBrack);
//     assert!(get_next_token(&mut b3) == ~String(~"A"));
//     assert!(get_next_token(&mut b3) == ~Dash);
//     assert!(get_next_token(&mut b3) == ~String(~"Z"));
//     assert!(get_next_token(&mut b3) == ~RBrack);
//     assert!(get_next_token(&mut b3) == ~RParen);
//     assert!(get_next_token(&mut b3) == ~Asterisk);

//     let mut b4 = LookaheadBuffer::new("letter (letter | digit)*");
//     assert!(get_next_token(&mut b4) == ~Id(~"letter"));
//     assert!(get_next_token(&mut b4) == ~LParen);
//     assert!(get_next_token(&mut b4) == ~Id(~"letter"));
//     assert!(get_next_token(&mut b4) == ~Bar);
//     assert!(get_next_token(&mut b4) == ~Id(~"digit"));
//     assert!(get_next_token(&mut b4) == ~RParen);
//     assert!(get_next_token(&mut b4) == ~Asterisk);
// }

// // regexp := union
// // union  := union '|' concat | concat
// // concat := concat factor | factor
// // factor := (regexp) | regexp'*' | regexp'+' | class | id | str
// // class  := '[' (char | range)* ']'
// // range  := char'-'char

// // parse a regexp from buffer until one of the terminators in term occurs
// pub fn parse_regexp(buffer: &mut LookaheadBuffer, term: &[~str]) -> ~Ast {
//     parse_union(buffer, term)
// }

// fn parse_union(buffer: &mut LookaheadBuffer, term: &[~str]) -> ~Ast {
//     let left = parse_concat(buffer, term);
//     if get_next_token(buffer) == ~Bar {
//         let right = parse_union(buffer, term);
//         ~Union(left, right)
//     }
//     else {
//         left
//     }
// }

// fn parse_concat(buffer: &mut LookaheadBuffer, term: &[~str]) -> ~Ast {
//     let left = parse_factor(buffer, term);
//     let right = parse_factor(buffer, term);
//     ~Conc(left, right)
// }

// fn trailing_closure(buffer: &mut LookaheadBuffer) -> Option<char> {
//     skip_whitespace(buffer);
//     match buffer.next_char() {
//         '*' => Some('*'),
//         '+' => Some('+'),
//         c => { buffer.return_char(c); None }
//     }
// }

// fn parse_character_class(buffer: &mut LookaheadBuffer) -> ~Ast {
//     ~Epsilon         // TODO
// }

// fn parse_factor(buffer: &mut LookaheadBuffer, term: &[~str]) -> ~Ast {
//     let pre = match get_next_token(buffer) {
//         ~LParen => { let e = parse_regexp(buffer, term);
//                      match_next_token(buffer, ~RParen);
//                      e }
//         ~LBrack => parse_character_class(buffer),
//         ~Id(s) => ~Symb(s),
//         ~String(s) => ~Str(s),  // TODO: check for END
//         _ => ~Epsilon        // TODO: error
//     };
//     match trailing_closure(buffer) {
//         Some('*') => ~Star(pre),
//         Some('+') => ~OnePlus(pre),
//         Some(_) => fail!("Unexpected closure character"),
//         None => pre
//     }
// }
<commit_msg>Updated regexp.rs<commit_after>//
// rslex - a lexer generator for rust
//
// regexp.rs
// Regexp parsing and representation
//
// Andrei de A. Formiga, 2013-08-09
//

extern mod std;

use buffer::LookaheadBuffer;
//use parser::skip_whitespace;

#[deriving(Eq)]
enum Token { LBrack, RBrack, Id(~str), LParen, RParen, Asterisk,
             Plus, Bar, Dash, String(~str), Eof }

enum Ast { Symb(~str), Str(~str), Union(~Ast, ~Ast),
           Conc(~Ast, ~Ast), Star(~Ast), OnePlus(~Ast),
           CharClass(char, char), Epsilon }

fn parse_string(buffer: &mut LookaheadBuffer, delim: char) -> ~str {
    let mut res : ~str = ~"";
    loop {
        match buffer.next_char() {
            None => fail!("Unexpected end of file. Expected closing {}", delim),
            Some(c) if c == delim => break,
            Some(c) => res.push_char(c)
        }
    }
    res
}

#[test]
fn test_parse_string() {
    let mut b1 = LookaheadBuffer::new("abc'* ");
    assert_eq!(parse_string(&mut b1, '\''), ~"abc");
    assert_eq!(b1.next_char(), Some('*'));

    let mut b2 = LookaheadBuffer::new("abc'def\"  ");
    assert_eq!(parse_string(&mut b2, '"'), ~"abc'def");
    assert_eq!(b2.next_char(), Some(' '));
}

#[test]
#[should_fail]
fn unclosed_string() {
    let mut b1 = LookaheadBuffer::new("abc'def  ");
    assert_eq!(parse_string(&mut b1, '"'), ~"abc'def");
}

#[inline]
fn is_id_char(c: char) -> bool {
    std::char::is_alphanumeric(c) || c == '_'
}

fn parse_id(buffer: &mut LookaheadBuffer, first: char) -> ~str {
    let mut res : ~str = ~"";
    res.push_char(first);
    loop {
        match buffer.next_char() {
            Some(c) if is_id_char(c) => res.push_char(c),
            Some(c) => { buffer.return_char(c); break }
            None => break
        }
    }
    res
}

#[test]
fn test_parse_id() {
    let mut b1 = LookaheadBuffer::new("abc'* ");
    assert_eq!(parse_id(&mut b1, 'x'), ~"xabc");
    assert_eq!(b1.next_char(), Some('\''));

    let mut b2 = LookaheadBuffer::new("bc_def   ");
    assert_eq!(parse_id(&mut b2, 'a'), ~"abc_def");

    let mut b3 = LookaheadBuffer::new("_times|'xy')*   ");
    assert_eq!(parse_id(&mut b3, 'n'), ~"n_times");
    assert_eq!(b3.next_char(), Some('|'));

    let mut b4 = LookaheadBuffer::new(" +xy)*   ");
    assert_eq!(parse_id(&mut b4, 'n'), ~"n");
    assert_eq!(b4.next_char(), Some(' '));
    assert_eq!(b4.next_char(), Some('+'));
    assert_eq!(b4.next_char(), Some('x'));
    assert_eq!(parse_id(&mut b4, 'x'), ~"xy");
}

#[inline]
fn match_next_token(buffer: &mut LookaheadBuffer, t: Token) {
    let rt = get_next_token(buffer);
    if rt != t {
        fail!("Unexpeced token: expected {:?}, got {:?}", t, rt);
    }
}

fn get_next_token(buffer: &mut LookaheadBuffer) -> Token {
    buffer.skip_whitespace();
    match buffer.next_char() {
        Some('[') => LBrack,
        Some(']') => RBrack,
        Some('(') => LParen,
        Some(')') => RParen,
        Some('*') => Asterisk,
        Some('+') => Plus,
        Some('|') => Bar,
        Some('-') => Dash,
        Some('\'') => String(parse_string(buffer, '\'')),
        Some('"') => String(parse_string(buffer, '"')),
        Some(c) if std::char::is_alphabetic(c) => Id(parse_id(buffer, c)),
        None => Eof,
        Some(c) => fail!("Unexpected character: {}", c)
    }
}

#[test]
fn test_get_next_token() {
    let mut b1 = LookaheadBuffer::new("'return'");
    assert_eq!(get_next_token(&mut b1), String(~"return"));

    let mut b2 = LookaheadBuffer::new("return");
    assert_eq!(get_next_token(&mut b2), Id(~"return"));

    let mut b3 = LookaheadBuffer::new("(['a'-'z'])(['A'-'Z'])*");
    assert_eq!(get_next_token(&mut b3), LParen);
    assert_eq!(get_next_token(&mut b3), LBrack);
    assert_eq!(get_next_token(&mut b3), String(~"a"));
    assert_eq!(get_next_token(&mut b3), Dash);
    assert_eq!(get_next_token(&mut b3), String(~"z"));
    assert_eq!(get_next_token(&mut b3), RBrack);
    assert_eq!(get_next_token(&mut b3), RParen);
    assert_eq!(get_next_token(&mut b3), LParen);
    assert_eq!(get_next_token(&mut b3), LBrack);
    assert_eq!(get_next_token(&mut b3), String(~"A"));
    assert_eq!(get_next_token(&mut b3), Dash);
    assert_eq!(get_next_token(&mut b3), String(~"Z"));
    assert_eq!(get_next_token(&mut b3), RBrack);
    assert_eq!(get_next_token(&mut b3), RParen);
    assert_eq!(get_next_token(&mut b3), Asterisk);

    let mut b4 = LookaheadBuffer::new("letter (letter | digit)*");
    assert_eq!(get_next_token(&mut b4), Id(~"letter"));
    assert_eq!(get_next_token(&mut b4), LParen);
    assert_eq!(get_next_token(&mut b4), Id(~"letter"));
    assert_eq!(get_next_token(&mut b4), Bar);
    assert_eq!(get_next_token(&mut b4), Id(~"digit"));
    assert_eq!(get_next_token(&mut b4), RParen);
    assert_eq!(get_next_token(&mut b4), Asterisk);
}

// regexp := union
// union  := union '|' concat | concat
// concat := concat factor | factor
// factor := (regexp) | regexp'*' | regexp'+' | class | id | str
// class  := '[' (char | range)* ']'
// range  := char'-'char

// parse a regexp from buffer until one of the terminators in term occurs
pub fn parse_regexp(buffer: &mut LookaheadBuffer, term: &[~str]) -> Ast {
    parse_union(buffer, term)
}

fn parse_union(buffer: &mut LookaheadBuffer, term: &[~str]) -> Ast {
    let left = parse_concat(buffer, term);
    if get_next_token(buffer) == Bar {
        let right = parse_union(buffer, term);
        Union(~left, ~right)
    }
    else {
        left
    }
}

fn parse_concat(buffer: &mut LookaheadBuffer, term: &[~str]) -> Ast {
    let left = parse_factor(buffer, term);
    let right = parse_factor(buffer, term);
    Conc(~left, ~right)
}

fn trailing_closure(buffer: &mut LookaheadBuffer) -> Option<char> {
    buffer.skip_whitespace();
    match buffer.next_char() {
        Some('*') => Some('*'),
        Some('+') => Some('+'),
        Some(c) => { buffer.return_char(c); None },
        None => None
    }
}

fn parse_character_class(buffer: &mut LookaheadBuffer) -> Ast {
    Epsilon         // TODO
}

fn parse_factor(buffer: &mut LookaheadBuffer, term: &[~str]) -> Ast {
    let pre = match get_next_token(buffer) {
        LParen => { let e = parse_regexp(buffer, term);
                    match_next_token(buffer, RParen);
                    e }
        LBrack => parse_character_class(buffer),
        Id(s) => Symb(s),
        String(s) => Str(s),  // TODO: check for END
        _ => Epsilon          // TODO: error
    };
    match trailing_closure(buffer) {
        Some('*') => Star(~pre),
        Some('+') => OnePlus(~pre),
        Some(_) => fail!("Unexpected closure character"),
        None => pre
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use document_loader::DocumentLoader;
use dom::bindings::codegen::Bindings::DOMImplementationBinding;
use dom::bindings::codegen::Bindings::DOMImplementationBinding::DOMImplementationMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::NodeCast;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root};
use dom::bindings::utils::validate_qualified_name;
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::document::DocumentSource;
use dom::document::{Document, IsHTMLDocument};
use dom::documenttype::DocumentType;
use dom::htmlbodyelement::HTMLBodyElement;
use dom::htmlheadelement::HTMLHeadElement;
use dom::htmlhtmlelement::HTMLHtmlElement;
use dom::htmltitleelement::HTMLTitleElement;
use dom::text::Text;
use std::borrow::ToOwned;
use util::str::DOMString;

// https://dom.spec.whatwg.org/#domimplementation
#[dom_struct]
pub struct DOMImplementation {
    reflector_: Reflector,
    document: JS<Document>,
}

impl DOMImplementation {
    fn new_inherited(document: &Document) -> DOMImplementation {
        DOMImplementation {
            reflector_: Reflector::new(),
            document: JS::from_ref(document),
        }
    }

    pub fn new(document: &Document) -> Root<DOMImplementation> {
        let window = document.window();
        reflect_dom_object(box DOMImplementation::new_inherited(document),
                           GlobalRef::Window(window),
                           DOMImplementationBinding::Wrap)
    }
}

// https://dom.spec.whatwg.org/#domimplementation
impl DOMImplementationMethods for DOMImplementation {
    // https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype
    fn CreateDocumentType(&self, qualified_name: DOMString, pubid: DOMString, sysid: DOMString)
                          -> Fallible<Root<DocumentType>> {
        try!(validate_qualified_name(&qualified_name));
        let document = self.document.root();
        Ok(DocumentType::new(qualified_name, Some(pubid), Some(sysid), document.r()))
    }

    // https://dom.spec.whatwg.org/#dom-domimplementation-createdocument
    fn CreateDocument(&self, namespace: Option<DOMString>, qname: DOMString,
                      maybe_doctype: Option<&DocumentType>) -> Fallible<Root<Document>> {
        let doc = self.document.root();
        let doc = doc.r();
        let win = doc.window();
        let loader = DocumentLoader::new(&*doc.loader());

        // Step 1.
        let doc = Document::new(win, None, IsHTMLDocument::NonHTMLDocument,
                                None, None, DocumentSource::NotFromParser, loader);
        // Step 2-3.
        let maybe_elem = if qname.is_empty() {
            None
        } else {
            match doc.r().CreateElementNS(namespace, qname) {
                Err(error) => return Err(error),
                Ok(elem) => Some(elem)
            }
        };

        {
            let doc_node = NodeCast::from_ref(doc.r());

            // Step 4.
            match maybe_doctype {
                None => (),
                Some(ref doctype) => {
                    let doc_type = NodeCast::from_ref(*doctype);
                    assert!(doc_node.AppendChild(doc_type).is_ok())
                }
            }

            // Step 5.
            match maybe_elem {
                None => (),
                Some(ref elem) => {
                    assert!(doc_node.AppendChild(NodeCast::from_ref(elem.r())).is_ok())
                }
            }
        }

        // Step 6.
        // FIXME: https://github.com/mozilla/servo/issues/1522

        // Step 7.
        Ok(doc)
    }

    // https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument
    fn CreateHTMLDocument(&self, title: Option<DOMString>) -> Root<Document> {
        let document = self.document.root();
        let document = document.r();
        let win = document.window();
        let loader = DocumentLoader::new(&*document.loader());

        // Step 1-2.
        let doc = Document::new(win, None, IsHTMLDocument::HTMLDocument, None, None,
                                DocumentSource::NotFromParser, loader);

        {
            // Step 3.
            let doc_node = NodeCast::from_ref(doc.r());
            let doc_type = DocumentType::new("html".to_owned(), None, None, doc.r());
            assert!(doc_node.AppendChild(NodeCast::from_ref(doc_type.r())).is_ok());
        }

        {
            // Step 4.
            let doc_node = NodeCast::from_ref(doc.r());
            let doc_html = NodeCast::from_root(
                HTMLHtmlElement::new("html".to_owned(), None, doc.r()));
            assert!(doc_node.AppendChild(doc_html.r()).is_ok());

            {
                // Step 5.
                let doc_head = NodeCast::from_root(
                    HTMLHeadElement::new("head".to_owned(), None, doc.r()));
                assert!(doc_html.r().AppendChild(doc_head.r()).is_ok());

                // Step 6.
                match title {
                    None => (),
                    Some(title_str) => {
                        // Step 6.1.
                        let doc_title = NodeCast::from_root(
                            HTMLTitleElement::new("title".to_owned(), None, doc.r()));
                        assert!(doc_head.r().AppendChild(doc_title.r()).is_ok());

                        // Step 6.2.
                        let title_text = Text::new(title_str, doc.r());
                        assert!(doc_title.r().AppendChild(NodeCast::from_ref(title_text.r())).is_ok());
                    }
                }
            }

            // Step 7.
            let doc_body = HTMLBodyElement::new("body".to_owned(), None, doc.r());
            assert!(doc_html.r().AppendChild(NodeCast::from_ref(doc_body.r())).is_ok());
        }

        // Step 8.
        // FIXME: https://github.com/mozilla/servo/issues/1522

        // Step 9.
        doc
    }

    // https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature
    fn HasFeature(&self) -> bool {
        true
    }
}
<commit_msg>Do not root DOMImplementation::document<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use document_loader::DocumentLoader;
use dom::bindings::codegen::Bindings::DOMImplementationBinding;
use dom::bindings::codegen::Bindings::DOMImplementationBinding::DOMImplementationMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::NodeCast;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root};
use dom::bindings::utils::validate_qualified_name;
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::document::DocumentSource;
use dom::document::{Document, IsHTMLDocument};
use dom::documenttype::DocumentType;
use dom::htmlbodyelement::HTMLBodyElement;
use dom::htmlheadelement::HTMLHeadElement;
use dom::htmlhtmlelement::HTMLHtmlElement;
use dom::htmltitleelement::HTMLTitleElement;
use dom::text::Text;
use std::borrow::ToOwned;
use util::str::DOMString;

// https://dom.spec.whatwg.org/#domimplementation
#[dom_struct]
pub struct DOMImplementation {
    reflector_: Reflector,
    document: JS<Document>,
}

impl DOMImplementation {
    fn new_inherited(document: &Document) -> DOMImplementation {
        DOMImplementation {
            reflector_: Reflector::new(),
            document: JS::from_ref(document),
        }
    }

    pub fn new(document: &Document) -> Root<DOMImplementation> {
        let window = document.window();
        reflect_dom_object(box DOMImplementation::new_inherited(document),
                           GlobalRef::Window(window),
                           DOMImplementationBinding::Wrap)
    }
}

// https://dom.spec.whatwg.org/#domimplementation
impl DOMImplementationMethods for DOMImplementation {
    // https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype
    fn CreateDocumentType(&self, qualified_name: DOMString, pubid: DOMString, sysid: DOMString)
                          -> Fallible<Root<DocumentType>> {
        try!(validate_qualified_name(&qualified_name));
        Ok(DocumentType::new(qualified_name, Some(pubid), Some(sysid), &self.document))
    }

    // https://dom.spec.whatwg.org/#dom-domimplementation-createdocument
    fn CreateDocument(&self, namespace: Option<DOMString>, qname: DOMString,
                      maybe_doctype: Option<&DocumentType>) -> Fallible<Root<Document>> {
        let win = self.document.window();
        let loader = DocumentLoader::new(&self.document.loader());

        // Step 1.
        let doc = Document::new(win, None, IsHTMLDocument::NonHTMLDocument,
                                None, None, DocumentSource::NotFromParser, loader);
        // Step 2-3.
        let maybe_elem = if qname.is_empty() {
            None
        } else {
            match doc.r().CreateElementNS(namespace, qname) {
                Err(error) => return Err(error),
                Ok(elem) => Some(elem)
            }
        };

        {
            let doc_node = NodeCast::from_ref(doc.r());

            // Step 4.
            match maybe_doctype {
                None => (),
                Some(ref doctype) => {
                    let doc_type = NodeCast::from_ref(*doctype);
                    assert!(doc_node.AppendChild(doc_type).is_ok())
                }
            }

            // Step 5.
            match maybe_elem {
                None => (),
                Some(ref elem) => {
                    assert!(doc_node.AppendChild(NodeCast::from_ref(elem.r())).is_ok())
                }
            }
        }

        // Step 6.
        // FIXME: https://github.com/mozilla/servo/issues/1522

        // Step 7.
        Ok(doc)
    }

    // https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument
    fn CreateHTMLDocument(&self, title: Option<DOMString>) -> Root<Document> {
        let win = self.document.window();
        let loader = DocumentLoader::new(&self.document.loader());

        // Step 1-2.
        let doc = Document::new(win, None, IsHTMLDocument::HTMLDocument, None, None,
                                DocumentSource::NotFromParser, loader);

        {
            // Step 3.
            let doc_node = NodeCast::from_ref(doc.r());
            let doc_type = DocumentType::new("html".to_owned(), None, None, doc.r());
            assert!(doc_node.AppendChild(NodeCast::from_ref(doc_type.r())).is_ok());
        }

        {
            // Step 4.
            let doc_node = NodeCast::from_ref(doc.r());
            let doc_html = NodeCast::from_root(
                HTMLHtmlElement::new("html".to_owned(), None, doc.r()));
            assert!(doc_node.AppendChild(doc_html.r()).is_ok());

            {
                // Step 5.
                let doc_head = NodeCast::from_root(
                    HTMLHeadElement::new("head".to_owned(), None, doc.r()));
                assert!(doc_html.r().AppendChild(doc_head.r()).is_ok());

                // Step 6.
                match title {
                    None => (),
                    Some(title_str) => {
                        // Step 6.1.
                        let doc_title = NodeCast::from_root(
                            HTMLTitleElement::new("title".to_owned(), None, doc.r()));
                        assert!(doc_head.r().AppendChild(doc_title.r()).is_ok());

                        // Step 6.2.
                        let title_text = Text::new(title_str, doc.r());
                        assert!(doc_title.r().AppendChild(NodeCast::from_ref(title_text.r())).is_ok());
                    }
                }
            }

            // Step 7.
            let doc_body = HTMLBodyElement::new("body".to_owned(), None, doc.r());
            assert!(doc_html.r().AppendChild(NodeCast::from_ref(doc_body.r())).is_ok());
        }

        // Step 8.
        // FIXME: https://github.com/mozilla/servo/issues/1522

        // Step 9.
        doc
    }

    // https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature
    fn HasFeature(&self) -> bool {
        true
    }
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/remove-letter-to-equalize-frequency/
pub fn equal_frequency(word: String) -> bool {
    todo!()
}

fn main() {
    println!("{}", equal_frequency("abcc".to_string())); // true
    println!("{}", equal_frequency("aazz".to_string())); // false
}
<commit_msg>Solve problem 2423<commit_after>use std::collections::HashMap;

// https://leetcode.com/problems/remove-letter-to-equalize-frequency/
pub fn equal_frequency(word: String) -> bool {
    let mut map1: HashMap<u8, i32> = HashMap::new();
    for b in word.as_bytes().iter() {
        *map1.entry(*b).or_insert(0) += 1;
    }
    if map1.len() == 1 {
        return true;
    }
    let mut map2: HashMap<i32, i32> = HashMap::new();
    for (_, count) in map1.iter() {
        *map2.entry(*count).or_insert(0) += 1;
    }
    if map2.len() == 1 {
        *map2.iter().next().unwrap().0 == 1
    } else if map2.len() == 2 {
        let mut iter = map2.iter();
        let (a, count1) = iter.next().unwrap();
        let (b, count2) = iter.next().unwrap();
        if *count1 > 1 && *count2 > 1 {
            return false;
        }
        i32::abs(a - b) == 1
    } else {
        false
    }
}

fn main() {
    println!("{}", equal_frequency("abcc".to_string())); // true
    println!("{}", equal_frequency("aazz".to_string())); // false
    println!("{}", equal_frequency("bac".to_string())); // true
    println!("{}", equal_frequency("ddaccb".to_string())); // false
    println!("{}", equal_frequency("aca".to_string())); // true
    println!("{}", equal_frequency("zz".to_string())); // true
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{protocols::network::SerializedRequest, ProtocolId};
use bytes::Bytes;
use serde::Serialize;
use std::fmt::Debug;

// TODO(philiphayes): just use wire::DirectSendMsg directly

#[derive(Clone, Eq, PartialEq, Serialize)]
pub struct Message {
    /// Message type.
    pub protocol_id: ProtocolId,
    /// Serialized message data.
    #[serde(skip)]
    pub mdata: Bytes,
}

impl Debug for Message {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mdata_str = if self.mdata.len() <= 10 {
            format!("{:?}", self.mdata)
        } else {
            format!("{:?}...", self.mdata.slice(..10))
        };
        write!(
            f,
            "Message {{ protocol: {:?}, mdata: {} }}",
            self.protocol_id, mdata_str
        )
    }
}

impl SerializedRequest for Message {
    fn protocol_id(&self) -> ProtocolId {
        self.protocol_id
    }

    fn data(&self) -> &Bytes {
        &self.mdata
    }
}
<commit_msg>[network] Add documentation for Direct Send Message<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{protocols::network::SerializedRequest, ProtocolId};
use bytes::Bytes;
use serde::Serialize;
use std::fmt::Debug;

#[derive(Clone, Eq, PartialEq, Serialize)]
pub struct Message {
    /// The [`ProtocolId`] for which of our upstream application modules should
    /// handle (i.e., deserialize and then respond to) this inbound rpc request.
    ///
    /// For example, if `protocol_id == ProtocolId::ConsensusRpc`, then this
    /// inbound rpc request will be dispatched to consensus for handling.
    pub protocol_id: ProtocolId,
    /// The serialized request data received from the sender. At this layer in
    /// the stack, the request data is just an opaque blob and will only be fully
    /// deserialized later in the handling application module.
    #[serde(skip)]
    pub mdata: Bytes,
}

impl Debug for Message {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mdata_str = if self.mdata.len() <= 10 {
            format!("{:?}", self.mdata)
        } else {
            format!("{:?}...", self.mdata.slice(..10))
        };
        write!(
            f,
            "Message {{ protocol: {:?}, mdata: {} }}",
            self.protocol_id, mdata_str
        )
    }
}

impl SerializedRequest for Message {
    fn protocol_id(&self) -> ProtocolId {
        self.protocol_id
    }

    fn data(&self) -> &Bytes {
        &self.mdata
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};

fn main() {
    assert_eq!(env::args_os().len(), 2);
    let test = PathBuf::from(env::args_os().nth(1).unwrap());
    let dst = Path::new("/data/local/tmp").join(test.file_name().unwrap());

    let status = Command::new("adb")
        .arg("wait-for-device")
        .status()
        .expect("failed to run rumprun-bake");
    assert!(status.success());

    let status = Command::new("adb")
        .arg("push")
        .arg(&test)
        .arg(&dst)
        .status()
        .expect("failed to run rumprun-bake");
    assert!(status.success());

    let output = Command::new("adb")
        .arg("shell")
        .arg(&dst)
        .output()
        .expect("failed to run rumprun-bake");
    assert!(status.success());

    println!("status: {}\nstdout ---\n{}\nstderr ---\n{}",
             output.status,
             String::from_utf8_lossy(&output.stdout),
             String::from_utf8_lossy(&output.stderr));

    let stdout = String::from_utf8_lossy(&output.stdout);
    let mut lines = stdout.lines().filter(|l| l.starts_with("PASSED "));
    if !lines.any(|l| l.contains(" tests")) {
        panic!("failed to find successful test run");
    }
}
<commit_msg>Update runtest-android<commit_after>use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};

fn main() {
    let args = env::args_os()
        .skip(1)
        .filter(|arg| arg != "--quiet")
        .collect::<Vec<_>>();
    assert_eq!(args.len(), 1);
    let test = PathBuf::from(&args[0]);
    let dst = Path::new("/data/local/tmp").join(test.file_name().unwrap());

    let status = Command::new("adb")
        .arg("wait-for-device")
        .status()
        .expect("failed to run: adb wait-for-device");
    assert!(status.success());

    let status = Command::new("adb")
        .arg("push")
        .arg(&test)
        .arg(&dst)
        .status()
        .expect("failed to run: adb pushr");
    assert!(status.success());

    let output = Command::new("adb")
        .arg("shell")
        .arg(&dst)
        .output()
        .expect("failed to run: adb shell");
    assert!(status.success());

    println!("status: {}\nstdout ---\n{}\nstderr ---\n{}",
             output.status,
             String::from_utf8_lossy(&output.stdout),
             String::from_utf8_lossy(&output.stderr));

    let stdout = String::from_utf8_lossy(&output.stdout);
    let mut lines = stdout.lines().filter(|l| l.starts_with("PASSED "));
    if !lines.any(|l| l.contains(" tests")) {
        panic!("failed to find successful test run");
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::json::Json;
use chrono::{DateTime, UTC, Timelike};
use byteorder::{WriteBytesExt, BigEndian};

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub enum Term {
    String(String),
    Boolean(bool),
    I64(i64),
    U64(u64),
    DateTime(DateTime<UTC>),
    //F64(f64),
    Null,
}

impl Term {
    pub fn from_json(json: &Json) -> Term {
        // TODO: Should be aware of mappings
        match *json {
            Json::String(ref string) => Term::String(string.clone()),
            Json::Boolean(value) => Term::Boolean(value),
            Json::F64(value) => Term::Null, //Term::F64(value),
            Json::I64(value) => Term::I64(value),
            Json::U64(value) => Term::U64(value),
            Json::Null => Term::Null,

            // These two are unsupported
            // TODO: Raise error
            Json::Array(_) => Term::Null,
            Json::Object(_) => Term::Null,
        }
    }

    pub fn as_json(&self) -> Json {
        match *self {
            Term::String(ref string) => Json::String(string.clone()),
            Term::Boolean(value) => Json::Boolean(value),
            //Term::F64(value) => Json::F64(value),
            Term::I64(value) => Json::I64(value),
            Term::U64(value) => Json::U64(value),
            Term::DateTime(value) => Json::String(value.to_rfc3339()),
            Term::Null => Json::Null,
        }
    }

    pub fn to_bytes(&self) -> Vec<u8> {
        match *self {
            Term::String(ref string) => {
                let mut bytes = Vec::with_capacity(1 + string.len());
                bytes.push(b's');

                for byte in string.as_bytes() {
                    bytes.push(*byte);
                }

                bytes
            },
            Term::Boolean(value) => {
                if value {
                    vec![b't']
                } else {
                    vec![b'f']
                }
            }
            Term::I64(value) => {
                let mut bytes = Vec::with_capacity(8);
                bytes.write_i64::<BigEndian>(value);
                bytes
            }
            Term::U64(value) => {
                let mut bytes = Vec::with_capacity(8);
                bytes.write_u64::<BigEndian>(value);
                bytes
            }
            Term::DateTime(value) => {
                let mut bytes = Vec::with_capacity(0);
                let timestamp = value.timestamp();
                let micros = value.nanosecond() / 1000;
                let timestamp_with_micros = timestamp * 1000000 + micros as i64;
                bytes.write_i64::<BigEndian>(timestamp_with_micros);
                bytes
            }
            Term::Null => {
                let mut bytes = Vec::with_capacity(1);
                bytes.push(b'\0');
                bytes
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use chrono::{DateTime, UTC, Timelike};
    use super::Term;

    #[test]
    fn test_string_to_bytes() {
        let term = Term::String("foo".to_string());

        assert_eq!(term.to_bytes(), vec![115, 102, 111, 111])
    }

    #[test]
    fn test_hiragana_string_to_bytes() {
        let term = Term::String("こんにちは".to_string());

        assert_eq!(term.to_bytes(), vec![115, 227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175])
    }

    #[test]
    fn test_blank_string_to_bytes() {
        let term = Term::String("".to_string());

        assert_eq!(term.to_bytes(), vec![115])
    }

    #[test]
    fn test_boolean_true_to_bytes() {
        let term = Term::Boolean(true);

        // 116 = 't' in ASCII
        assert_eq!(term.to_bytes(), vec![116])
    }

    #[test]
    fn test_boolean_false_to_bytes() {
        let term = Term::Boolean(false);

        // 102 = 'f' in ASCII
        assert_eq!(term.to_bytes(), vec![102])
    }

    #[test]
    fn test_i64_to_bytes() {
        let term = Term::I64(123);

        assert_eq!(term.to_bytes(), vec![0, 0, 0, 0, 0, 0, 0, 123])
    }

    #[test]
    fn test_negative_i64_to_bytes() {
        let term = Term::I64(-123);

        assert_eq!(term.to_bytes(), vec![255, 255, 255, 255, 255, 255, 255, 133])
    }

    #[test]
    fn test_u64_to_bytes() {
        let term = Term::U64(123);

        assert_eq!(term.to_bytes(), vec![0, 0, 0, 0, 0, 0, 0, 123])
    }

    #[test]
    fn test_datetime_to_bytes() {
        let date = "2016-07-23T16:15:00+01:00".parse::<DateTime<UTC>>().unwrap();
        let term = Term::DateTime(date);

        assert_eq!(term.to_bytes(), vec![0, 5, 56, 79, 3, 191, 101, 0])
    }

    #[test]
    fn test_datetime_with_microseconds_to_bytes() {
        let mut date = "2016-07-23T16:15:00+01:00".parse::<DateTime<UTC>>().unwrap();
        date = date.with_nanosecond(123123123).unwrap();
        let term = Term::DateTime(date);

        // This is exactly 123123 higher than the result of "test_datetime_to_bytes"
        assert_eq!(term.to_bytes(), vec![0, 5, 56, 79, 3, 193, 69, 243])
    }

    #[test]
    fn test_datetime_with_different_timezone_to_bytes() {
        let date = "2016-07-23T16:15:00+02:00".parse::<DateTime<UTC>>().unwrap();
        let term = Term::DateTime(date);

        // This is exactly 3_600_000_000 lower than the result of "test_datetime_to_bytes"
        assert_eq!(term.to_bytes(), vec![0, 5, 56, 78, 45, 43, 193, 0])
    }

    #[test]
    fn test_null_to_bytes() {
        let term = Term::Null;

        assert_eq!(term.to_bytes(), vec![0])
    }
}
<commit_msg>Remove 's' prefix from bytes representation of string terms<commit_after>use rustc_serialize::json::Json;
use chrono::{DateTime, UTC, Timelike};
use byteorder::{WriteBytesExt, BigEndian};

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub enum Term {
    String(String),
    Boolean(bool),
    I64(i64),
    U64(u64),
    DateTime(DateTime<UTC>),
    //F64(f64),
    Null,
}

impl Term {
    pub fn from_json(json: &Json) -> Term {
        // TODO: Should be aware of mappings
        match *json {
            Json::String(ref string) => Term::String(string.clone()),
            Json::Boolean(value) => Term::Boolean(value),
            Json::F64(value) => Term::Null, //Term::F64(value),
            Json::I64(value) => Term::I64(value),
            Json::U64(value) => Term::U64(value),
            Json::Null => Term::Null,

            // These two are unsupported
            // TODO: Raise error
            Json::Array(_) => Term::Null,
            Json::Object(_) => Term::Null,
        }
    }

    pub fn as_json(&self) -> Json {
        match *self {
            Term::String(ref string) => Json::String(string.clone()),
            Term::Boolean(value) => Json::Boolean(value),
            //Term::F64(value) => Json::F64(value),
            Term::I64(value) => Json::I64(value),
            Term::U64(value) => Json::U64(value),
            Term::DateTime(value) => Json::String(value.to_rfc3339()),
            Term::Null => Json::Null,
        }
    }

    pub fn to_bytes(&self) -> Vec<u8> {
        match *self {
            Term::String(ref string) => {
                let mut bytes = Vec::with_capacity(string.len());

                for byte in string.as_bytes() {
                    bytes.push(*byte);
                }

                bytes
            },
            Term::Boolean(value) => {
                if value {
                    vec![b't']
                } else {
                    vec![b'f']
                }
            }
            Term::I64(value) => {
                let mut bytes = Vec::with_capacity(8);
                bytes.write_i64::<BigEndian>(value);
                bytes
            }
            Term::U64(value) => {
                let mut bytes = Vec::with_capacity(8);
                bytes.write_u64::<BigEndian>(value);
                bytes
            }
            Term::DateTime(value) => {
                let mut bytes = Vec::with_capacity(0);
                let timestamp = value.timestamp();
                let micros = value.nanosecond() / 1000;
                let timestamp_with_micros = timestamp * 1000000 + micros as i64;
                bytes.write_i64::<BigEndian>(timestamp_with_micros);
                bytes
            }
            Term::Null => {
                let mut bytes = Vec::with_capacity(1);
                bytes.push(b'\0');
                bytes
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use chrono::{DateTime, UTC, Timelike};
    use super::Term;

    #[test]
    fn test_string_to_bytes() {
        let term = Term::String("foo".to_string());

        assert_eq!(term.to_bytes(), vec![102, 111, 111])
    }

    #[test]
    fn test_hiragana_string_to_bytes() {
        let term = Term::String("こんにちは".to_string());

        assert_eq!(term.to_bytes(), vec![227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175])
    }

    #[test]
    fn test_blank_string_to_bytes() {
        let term = Term::String("".to_string());

        assert_eq!(term.to_bytes(), vec![])
    }

    #[test]
    fn test_boolean_true_to_bytes() {
        let term = Term::Boolean(true);

        // 116 = 't' in ASCII
        assert_eq!(term.to_bytes(), vec![116])
    }

    #[test]
    fn test_boolean_false_to_bytes() {
        let term = Term::Boolean(false);

        // 102 = 'f' in ASCII
        assert_eq!(term.to_bytes(), vec![102])
    }

    #[test]
    fn test_i64_to_bytes() {
        let term = Term::I64(123);

        assert_eq!(term.to_bytes(), vec![0, 0, 0, 0, 0, 0, 0, 123])
    }

    #[test]
    fn test_negative_i64_to_bytes() {
        let term = Term::I64(-123);

        assert_eq!(term.to_bytes(), vec![255, 255, 255, 255, 255, 255, 255, 133])
    }

    #[test]
    fn test_u64_to_bytes() {
        let term = Term::U64(123);

        assert_eq!(term.to_bytes(), vec![0, 0, 0, 0, 0, 0, 0, 123])
    }

    #[test]
    fn test_datetime_to_bytes() {
        let date = "2016-07-23T16:15:00+01:00".parse::<DateTime<UTC>>().unwrap();
        let term = Term::DateTime(date);

        assert_eq!(term.to_bytes(), vec![0, 5, 56, 79, 3, 191, 101, 0])
    }

    #[test]
    fn test_datetime_with_microseconds_to_bytes() {
        let mut date = "2016-07-23T16:15:00+01:00".parse::<DateTime<UTC>>().unwrap();
        date = date.with_nanosecond(123123123).unwrap();
        let term = Term::DateTime(date);

        // This is exactly 123123 higher than the result of "test_datetime_to_bytes"
        assert_eq!(term.to_bytes(), vec![0, 5, 56, 79, 3, 193, 69, 243])
    }

    #[test]
    fn test_datetime_with_different_timezone_to_bytes() {
        let date = "2016-07-23T16:15:00+02:00".parse::<DateTime<UTC>>().unwrap();
        let term = Term::DateTime(date);

        // This is exactly 3_600_000_000 lower than the result of "test_datetime_to_bytes"
        assert_eq!(term.to_bytes(), vec![0, 5, 56, 78, 45, 43, 193, 0])
    }

    #[test]
    fn test_null_to_bytes() {
        let term = Term::Null;

        assert_eq!(term.to_bytes(), vec![0])
    }
}
<|endoftext|>


<commit_before>mod error;

use std::convert::{TryFrom, TryInto};

use fleetspeak::Packet;
use log::error;

use crate::action;
pub use self::error::{Error, ParseError};

pub type Result<T> = std::result::Result<T, Error>;

pub fn execute<S, R, H>(session: &mut S, handler: H, payload: Payload) -> Result<()>
where
    S: Session,
    R: action::Request,
    H: FnOnce(&mut S, R) -> Result<()>,
{
    handler(session, payload.parse()?)
}

pub fn handle<M>(message: M)
where
    M: TryInto<Demand, Error=ParseError>,
{
    let demand = match message.try_into() {
        Ok(demand) => demand,
        Err(error) => {
            error!("failed to parse the message: {}", error);
            return;
        }
    };

    let mut session = Action::new(demand.header.clone());

    // TODO: Send status message.
    let _result = action::dispatch(&demand.action, &mut session, demand.payload);
}

pub trait Session {
    fn send<R: action::Response>(&mut self, response: R) -> Result<()>;
}

pub struct Action {
    header: Header,
    next_response_id: u64,
}

impl Action {

    pub fn new(header: Header) -> Action {
        Action {
            header: header,
            next_response_id: 0,
        }
    }
}

impl Session for Action {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: self.header.session_id.clone(),
            request_id: Some(self.header.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }.send()?;

        self.next_response_id += 1;

        Ok(())
    }
}

pub struct Sink {
    id: &'static str,
}

impl Session for Sink {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: String::from(self.id),
            request_id: None,
            response_id: None,
            data: response,
        }.send()
    }
}

pub fn startup() -> Sink {
    Sink { id: "/flows/F:Startup" }
}

pub struct Demand {
    pub action: String,
    pub header: Header,
    pub payload: Payload,
}

impl TryFrom<rrg_proto::GrrMessage> for Demand {

    type Error = ParseError;

    fn try_from(message: rrg_proto::GrrMessage)
    -> std::result::Result<Demand, ParseError>
    {
        use ParseError::*;

        let header = Header {
            session_id: message.session_id.ok_or(MissingField("session id"))?,
            request_id: message.request_id.ok_or(MissingField("request id"))?,
        };

        Ok(Demand {
            action: message.name.ok_or(MissingField("action name"))?,
            header: header,
            payload: Payload(message.args),
        })
    }
}

#[derive(Clone, Debug)]
pub struct Header {
    pub session_id: String,
    pub request_id: u64,
}

#[derive(Debug)]
pub struct Payload(Option<Vec<u8>>);

impl Payload {

    pub fn parse<R>(&self) -> std::result::Result<R, ParseError>
    where
        R: action::Request,
    {
        let proto = match self {
            Payload(Some(bytes)) => prost::Message::decode(&bytes[..])?,
            Payload(None) => Default::default(),
        };

        Ok(R::from_proto(proto))
    }
}

// TODO: This type should not be exposed.
pub struct Request<R: action::Request> {
    pub name: String,
    pub session_id: String,
    pub request_id: u64,
    pub data: R,
}

impl<R: action::Request> TryFrom<rrg_proto::GrrMessage> for Request<R> {

    type Error = ParseError;

    fn try_from(message: rrg_proto::GrrMessage)
    -> std::result::Result<Request<R>, ParseError>
    {
        use ParseError::*;

        let name = message.name.ok_or(MissingField("action name"))?;
        let session_id = message.session_id.ok_or(MissingField("session id"))?;
        let request_id = message.request_id.ok_or(MissingField("request id"))?;

        let proto = match message.args {
            Some(bytes) => prost::Message::decode(&bytes[..])?,
            None => Default::default(),
        };

        Ok(Request {
            name: name,
            session_id: session_id,
            request_id: request_id,
            data: R::from_proto(proto),
        })
    }
}

struct Response<R: action::Response> {
    session_id: String,
    request_id: Option<u64>,
    response_id: Option<u64>,
    data: R,
}

impl<R: action::Response> Response<R> {

    fn send(self) -> Result<()> {
        let message = self.try_into()?;
        send(message);

        Ok(())
    }
}

impl<R: action::Response> TryInto<rrg_proto::GrrMessage> for Response<R> {

    type Error = prost::EncodeError;

    fn try_into(self)
    -> std::result::Result<rrg_proto::GrrMessage, prost::EncodeError>
    {
        let mut data = Vec::new();
        prost::Message::encode(&self.data.into_proto(), &mut data)?;

        Ok(rrg_proto::GrrMessage {
            session_id: Some(self.session_id),
            response_id: self.response_id,
            request_id: self.request_id,
            r#type: Some(rrg_proto::grr_message::Type::Message.into()),
            args_rdf_name: R::RDF_NAME.map(String::from),
            args: Some(data),
            ..Default::default()
        })
    }
}

struct Status {
    session_id: String,
    request_id: u64,
    result: Result<()>,
}

impl TryInto<rrg_proto::GrrMessage> for Status {

    type Error = prost::EncodeError;

    fn try_into(self)
    -> std::result::Result<rrg_proto::GrrMessage, prost::EncodeError> {
        let status = match self.result {
            Ok(()) => rrg_proto::GrrStatus {
                status: Some(rrg_proto::grr_status::ReturnedStatus::Ok.into()),
                ..Default::default()
            },
            Err(error) => rrg_proto::GrrStatus {
                status: Some(rrg_proto::grr_status::ReturnedStatus::GenericError.into()),
                error_message: Some(error.to_string()),
                ..Default::default()
            },
        };

        let mut data = Vec::new();
        prost::Message::encode(&status, &mut data)?;

        Ok(rrg_proto::GrrMessage {
            session_id: Some(self.session_id),
            response_id: Some(self.request_id),
            r#type: Some(rrg_proto::grr_message::Type::Status.into()),
            args_rdf_name: Some(String::from("GrrStatus")),
            args: Some(data),
            ..Default::default()
        })
    }
}

fn send(message: rrg_proto::GrrMessage) {
        let packet = Packet {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data: message,
        };

        if let Err(error) = fleetspeak::send(packet) {
            // If we failed to deliver the message through Fleetspeak, it means
            // that our communication is broken (e.g. the pipe was closed) and
            // the agent should be killed.
            panic!("message delivery failure: {}", error)
        };
}
<commit_msg>Add support for sending final session status.<commit_after>mod error;

use std::convert::{TryFrom, TryInto};

use fleetspeak::Packet;
use log::error;

use crate::action;
pub use self::error::{Error, ParseError};

pub type Result<T> = std::result::Result<T, Error>;

pub fn execute<S, R, H>(session: &mut S, handler: H, payload: Payload) -> Result<()>
where
    S: Session,
    R: action::Request,
    H: FnOnce(&mut S, R) -> Result<()>,
{
    handler(session, payload.parse()?)
}

pub fn handle<M>(message: M)
where
    M: TryInto<Demand, Error=ParseError>,
{
    let demand = match message.try_into() {
        Ok(demand) => demand,
        Err(error) => {
            error!("failed to parse the message: {}", error);
            return;
        }
    };

    let mut session = Action::new(demand.header.clone());
    let result = action::dispatch(&demand.action, &mut session, demand.payload);

    let status = Status {
        header: demand.header,
        result: result,
    };

    let message = match status.try_into() {
        Ok(message) => message,
        Err(error) => {
            // If we cannot encode the final status message, there is nothing
            // we can do to notify the server, as status is responsible for
            // reporting errors. We can only log the error and carry on.
            error!("failed to encode status message: {}", error);
            return;
        }
    };

    send(message);
}

pub trait Session {
    fn send<R: action::Response>(&mut self, response: R) -> Result<()>;
}

pub struct Action {
    header: Header,
    next_response_id: u64,
}

impl Action {

    pub fn new(header: Header) -> Action {
        Action {
            header: header,
            next_response_id: 0,
        }
    }
}

impl Session for Action {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: self.header.session_id.clone(),
            request_id: Some(self.header.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }.send()?;

        self.next_response_id += 1;

        Ok(())
    }
}

pub struct Sink {
    id: &'static str,
}

impl Session for Sink {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: String::from(self.id),
            request_id: None,
            response_id: None,
            data: response,
        }.send()
    }
}

pub fn startup() -> Sink {
    Sink { id: "/flows/F:Startup" }
}

pub struct Demand {
    pub action: String,
    pub header: Header,
    pub payload: Payload,
}

impl TryFrom<rrg_proto::GrrMessage> for Demand {

    type Error = ParseError;

    fn try_from(message: rrg_proto::GrrMessage)
    -> std::result::Result<Demand, ParseError>
    {
        use ParseError::*;

        let header = Header {
            session_id: message.session_id.ok_or(MissingField("session id"))?,
            request_id: message.request_id.ok_or(MissingField("request id"))?,
        };

        Ok(Demand {
            action: message.name.ok_or(MissingField("action name"))?,
            header: header,
            payload: Payload(message.args),
        })
    }
}

#[derive(Clone, Debug)]
pub struct Header {
    pub session_id: String,
    pub request_id: u64,
}

#[derive(Debug)]
pub struct Payload(Option<Vec<u8>>);

impl Payload {

    pub fn parse<R>(&self) -> std::result::Result<R, ParseError>
    where
        R: action::Request,
    {
        let proto = match self {
            Payload(Some(bytes)) => prost::Message::decode(&bytes[..])?,
            Payload(None) => Default::default(),
        };

        Ok(R::from_proto(proto))
    }
}

// TODO: This type should not be exposed.
pub struct Request<R: action::Request> {
    pub name: String,
    pub session_id: String,
    pub request_id: u64,
    pub data: R,
}

impl<R: action::Request> TryFrom<rrg_proto::GrrMessage> for Request<R> {

    type Error = ParseError;

    fn try_from(message: rrg_proto::GrrMessage)
    -> std::result::Result<Request<R>, ParseError>
    {
        use ParseError::*;

        let name = message.name.ok_or(MissingField("action name"))?;
        let session_id = message.session_id.ok_or(MissingField("session id"))?;
        let request_id = message.request_id.ok_or(MissingField("request id"))?;

        let proto = match message.args {
            Some(bytes) => prost::Message::decode(&bytes[..])?,
            None => Default::default(),
        };

        Ok(Request {
            name: name,
            session_id: session_id,
            request_id: request_id,
            data: R::from_proto(proto),
        })
    }
}

struct Response<R: action::Response> {
    session_id: String,
    request_id: Option<u64>,
    response_id: Option<u64>,
    data: R,
}

impl<R: action::Response> Response<R> {

    fn send(self) -> Result<()> {
        let message = self.try_into()?;
        send(message);

        Ok(())
    }
}

impl<R: action::Response> TryInto<rrg_proto::GrrMessage> for Response<R> {

    type Error = prost::EncodeError;

    fn try_into(self)
    -> std::result::Result<rrg_proto::GrrMessage, prost::EncodeError>
    {
        let mut data = Vec::new();
        prost::Message::encode(&self.data.into_proto(), &mut data)?;

        Ok(rrg_proto::GrrMessage {
            session_id: Some(self.session_id),
            response_id: self.response_id,
            request_id: self.request_id,
            r#type: Some(rrg_proto::grr_message::Type::Message.into()),
            args_rdf_name: R::RDF_NAME.map(String::from),
            args: Some(data),
            ..Default::default()
        })
    }
}

struct Status {
    header: Header,
    result: Result<()>,
}

impl TryInto<rrg_proto::GrrMessage> for Status {

    type Error = prost::EncodeError;

    fn try_into(self)
    -> std::result::Result<rrg_proto::GrrMessage, prost::EncodeError> {
        let status = match self.result {
            Ok(()) => rrg_proto::GrrStatus {
                status: Some(rrg_proto::grr_status::ReturnedStatus::Ok.into()),
                ..Default::default()
            },
            Err(error) => rrg_proto::GrrStatus {
                status: Some(rrg_proto::grr_status::ReturnedStatus::GenericError.into()),
                error_message: Some(error.to_string()),
                ..Default::default()
            },
        };

        let mut data = Vec::new();
        prost::Message::encode(&status, &mut data)?;

        Ok(rrg_proto::GrrMessage {
            session_id: Some(self.header.session_id),
            response_id: Some(self.header.request_id),
            r#type: Some(rrg_proto::grr_message::Type::Status.into()),
            args_rdf_name: Some(String::from("GrrStatus")),
            args: Some(data),
            ..Default::default()
        })
    }
}

fn send(message: rrg_proto::GrrMessage) {
        let packet = Packet {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data: message,
        };

        if let Err(error) = fleetspeak::send(packet) {
            // If we failed to deliver the message through Fleetspeak, it means
            // that our communication is broken (e.g. the pipe was closed) and
            // the agent should be killed.
            panic!("message delivery failure: {}", error)
        };
}
<|endoftext|>