<commit_before>use super::geom::*;
use super::component::*;
use super::event::*;
use super::render::*;

use modular_flow as mf;

use gfx_device_gl as gl;

use std::rc::{Rc, Weak};
use std::cell::{Cell, RefCell};
use std::sync::Arc;

pub trait JackBackend {
    fn label(&self) -> &str;
    fn connect(&self, other: &Self);
    fn disconnect(&self);
}

impl JackBackend for Arc<mf::Port> {
    fn label(&self) -> &str {
        self.meta().name()
    }
    fn connect(&self, other: &Self) {
        mf::Port::connect(self, other).unwrap();
    }
    fn disconnect(&self) {
        mf::Port::disconnect(self).unwrap();
    }
}

/// Jacks are GUI connection points
/// wires (pipes) can connect jacks
pub struct Jack<T: JackBackend> {
    jack_ctx: Weak<JackContext<T>>,
    backend: T,
    bounds: Cell<Box3>,
    origin: Cell<Pt3>,
    connection: RefCell<Connection<T>>,
}

enum Connection<T: JackBackend> {
    None,
    /// head/tail distinction is so that only one endpoint draws the wire
    Head {
        endpoint: Weak<Jack<T>>,
    },
    Tail {
        endpoint: Weak<Jack<T>>,
    },
    /// floating is a connection in process
    Floating {
        pos: Pt2,
    },
}
impl<T: JackBackend> Connection<T> {
    fn is_connected(&self) -> bool {
        self.endpoint().is_some()
    }
    fn endpoint(&self) -> Option<Rc<Jack<T>>> {
        match self {
            Connection::Head {
                endpoint,
            }
            | Connection::Tail {
                endpoint,
            } => endpoint.upgrade(),
            _ => None,
        }
    }
    fn disconnect(&mut self) {
        if self.is_connected() {
            self.endpoint()
                .map(|endpoint| endpoint.connection.replace(Connection::None));
            *self = Connection::None;
        }
    }
}

impl<T: JackBackend> Jack<T> {
    fn new(jack_ctx: &Rc<JackContext<T>>, backend: T, bounds: Box3, origin: Pt3) -> Jack<T> {
        Jack {
            jack_ctx: Rc::downgrade(jack_ctx),
            backend,
            bounds: Cell::new(bounds),
            origin: Cell::new(origin),
            connection: RefCell::new(Connection::None),
        }
    }
    pub fn origin(&self) -> Pt3 {
        self.origin.get()
    }
    pub fn set_origin(&self, origin: Pt3) {
        self.origin.set(origin);
    }
    pub fn connection_point(&self) -> Pt3 {
        self.bounds.get().pos + self.bounds.get().size.y / 2.0 + self.origin()
    }
}
impl<T: JackBackend> GuiComponent for Rc<Jack<T>> {
    fn set_bounds(&mut self, bounds: Box3) {
        self.bounds.set(bounds);
    }
    fn bounds(&self) -> Box3 {
        self.bounds.get()
    }
    fn intersect(&self, pos: Pt2) -> bool {
        self.bounds().flatten().drop_z().intersect(pos)
    }
    fn render(&mut self, device: &mut gl::Device, ctx: &mut RenderContext) {
        const BORDER_SIZE: f32 = 1.0;
        const PAD: f32 = 2.0;
        let port_size = self.bounds().size.y;
        ctx.draw_rect(
            Rect3::new(
                self.bounds().pos + Pt3::new(PAD, PAD, 0.0),
                (port_size - PAD * 2.0).into(),
            ),
            [1.0, 1.0, 1.0],
        );
        ctx.draw_rect(
            Rect3::new(
                self.bounds().pos + Pt3::new(PAD + BORDER_SIZE, PAD + BORDER_SIZE, 0.0),
                (port_size - PAD * 2.0 - BORDER_SIZE * 2.0).into(),
            ),
            [0.0, 0.0, 0.5],
        );
        ctx.draw_text(
            self.backend.label(),
            self.bounds().pos + Pt3::new(20.0, 0.0, 0.0),
            [1.0, 1.0, 1.0],
        );
    }
    fn handle(&mut self, event: &Event) {
        match event.data {
            EventData::Click(pos, button, state) => {
                if event.focus && state == ButtonState::Pressed && button == MouseButton::Left
                    && self.bounds().flatten().drop_z().intersect(pos)
                {
                    let ctx = self.jack_ctx
                        .upgrade()
                        .expect("no events expected during shutdown");
                    let mut in_progress = ctx.in_progress.borrow_mut();
                    let mut connection = self.connection.borrow_mut();
                    if let Some((ref mut weak_in_progress, ref mut endpoint)) = in_progress
                        .take()
                        .and_then(|wip| wip.upgrade().map(|ep| (wip, ep)))
                    {
                        if !Rc::ptr_eq(endpoint, self) {
                            // connection in progress:
                            // click establishes new connection

                            // signal disconnect to backend
                            if connection.is_connected() {
                                self.backend.disconnect();
                            }
                            // update model
                            connection.disconnect();
                            *connection = Connection::Tail {
                                endpoint: weak_in_progress.clone(),
                            };
                            *endpoint.connection.borrow_mut() = Connection::Head {
                                endpoint: Rc::downgrade(self),
                            };
                            // signal connect to backend
                            self.backend.connect(&endpoint.backend);
                        } else {
                            // replace in_progress (taken above) if we decide to bail out
                            *in_progress = Some(weak_in_progress.clone());
                        }
                    } else {
                        // no connection in progress:
                        // begin connecting

                        // signal disconnect to backend
                        if connection.is_connected() {
                            self.backend.disconnect();
                        }
                        // update model
                        connection.disconnect();
                        *connection = Connection::Floating {
                            pos: pos + self.origin().drop_z(),
                        };
                        *in_progress = Some(Rc::downgrade(self));
                    }
                }
            }
            EventData::MouseMove(mouse_pos) => match *self.connection.borrow_mut() {
                Connection::Floating {
                    ref mut pos,
                } => {
                    *pos = mouse_pos + self.origin().drop_z();
                }
                _ => {}
            },
        }
    }
}

/// a Jack is unaware of other nearby jacks it can connect to
/// so the JackContext manages establishment of connections between jacks
/// (within a specific context)
pub struct JackContext<T: JackBackend> {
    bounds: Cell<Box3>,
    jacks: RefCell<Vec<Weak<Jack<T>>>>,
    in_progress: RefCell<Option<Weak<Jack<T>>>>,
}

impl<T: JackBackend> JackContext<T> {
    pub fn new(bounds: Box3) -> Rc<JackContext<T>> {
        Rc::new(JackContext {
            bounds: Cell::new(bounds),
            jacks: RefCell::new(Vec::new()),
            in_progress: RefCell::new(None),
        })
    }
    pub fn new_jack(self: &Rc<JackContext<T>>, backend: T, bounds: Box3, origin: Pt3) -> Rc<Jack<T>> {
        let jack = Rc::new(Jack::new(&self, backend, bounds, origin));
        let mut jacks = self.jacks.borrow_mut();
        weak_cleanup(&mut jacks);
        jacks.push(Rc::downgrade(&jack));
        jack
    }
}

/// Drop dropped Weak Ts
fn weak_cleanup<T>(vec: &mut Vec<Weak<T>>) {
    vec.retain(|x| x.upgrade().is_some());
}

/// the wires fill space outside of the modules, so they are rendered by the context
impl<T: JackBackend> GuiComponent for Rc<JackContext<T>> {
    fn set_bounds(&mut self, bounds: Box3) {
        self.bounds.set(bounds);
    }
    fn bounds(&self) -> Box3 {
        self.bounds.get()
    }
    fn intersect(&self, pos: Pt2) -> bool {
        self.bounds().flatten().drop_z().intersect(pos)
    }
    fn render(&mut self, device: &mut gl::Device, ctx: &mut RenderContext) {
        let jacks = self.jacks.borrow();
        for jack in jacks.iter() {
            if let Some(jack) = jack.upgrade() {
                match *jack.connection.borrow() {
                    Connection::Head {
                        ref endpoint,
                    } => {
                        if let Some(endpoint) = endpoint.upgrade() {
                            ctx.draw_pipe(&[
                                jack.connection_point().drop_z().with_z(0.0),
                                endpoint.connection_point().drop_z().with_z(0.0),
                            ]);
                        }
                    }
                    Connection::Floating {
                        pos,
                    } => {
                        ctx.draw_pipe(&[
                            jack.connection_point().drop_z().with_z(0.0),
                            pos.with_z(0.0),
                        ]);
                    }
                    _ => {}
                }
            }
        }
    }
    fn handle(&mut self, event: &Event) {}
}
<commit_msg>simplify<commit_after>use super::geom::*;
use super::component::*;
use super::event::*;
use super::render::*;

use modular_flow as mf;

use gfx_device_gl as gl;

use std::rc::{Rc, Weak};
use std::cell::{Cell, RefCell};
use std::sync::Arc;

pub trait JackBackend {
    fn label(&self) -> &str;
    fn connect(&self, other: &Self);
    fn disconnect(&self);
}

impl JackBackend for Arc<mf::Port> {
    fn label(&self) -> &str {
        self.meta().name()
    }
    fn connect(&self, other: &Self) {
        mf::Port::connect(self, other).unwrap();
    }
    fn disconnect(&self) {
        mf::Port::disconnect(self).unwrap();
    }
}

/// Jacks are GUI connection points
/// wires (pipes) can connect jacks
pub struct Jack<T: JackBackend> {
    jack_ctx: Weak<JackContext<T>>,
    backend: T,
    bounds: Cell<Box3>,
    origin: Cell<Pt3>,
    connection: RefCell<Connection<T>>,
}

enum Connection<T: JackBackend> {
    None,
    /// head/tail distinction is so that only one endpoint draws the wire
    Head {
        endpoint: Weak<Jack<T>>,
    },
    Tail {
        endpoint: Weak<Jack<T>>,
    },
    /// floating is a connection in process
    Floating {
        pos: Pt2,
    },
}
impl<T: JackBackend> Connection<T> {
    fn is_connected(&self) -> bool {
        self.endpoint().is_some()
    }
    fn endpoint(&self) -> Option<Rc<Jack<T>>> {
        match self {
            Connection::Head {
                endpoint,
            }
            | Connection::Tail {
                endpoint,
            } => endpoint.upgrade(),
            _ => None,
        }
    }
    fn disconnect(&mut self) {
        if self.is_connected() {
            self.endpoint()
                .map(|endpoint| endpoint.connection.replace(Connection::None));
            *self = Connection::None;
        }
    }
}

impl<T: JackBackend> Jack<T> {
    fn new(jack_ctx: &Rc<JackContext<T>>, backend: T, bounds: Box3, origin: Pt3) -> Jack<T> {
        Jack {
            jack_ctx: Rc::downgrade(jack_ctx),
            backend,
            bounds: Cell::new(bounds),
            origin: Cell::new(origin),
            connection: RefCell::new(Connection::None),
        }
    }
    pub fn origin(&self) -> Pt3 {
        self.origin.get()
    }
    pub fn set_origin(&self, origin: Pt3) {
        self.origin.set(origin);
    }
    pub fn connection_point(&self) -> Pt3 {
        self.bounds.get().pos + self.bounds.get().size.y / 2.0 + self.origin()
    }
}
impl<T: JackBackend> GuiComponent for Rc<Jack<T>> {
    fn set_bounds(&mut self, bounds: Box3) {
        self.bounds.set(bounds);
    }
    fn bounds(&self) -> Box3 {
        self.bounds.get()
    }
    fn intersect(&self, pos: Pt2) -> bool {
        self.bounds().flatten().drop_z().intersect(pos)
    }
    fn render(&mut self, device: &mut gl::Device, ctx: &mut RenderContext) {
        const BORDER_SIZE: f32 = 1.0;
        const PAD: f32 = 2.0;
        let port_size = self.bounds().size.y;
        ctx.draw_rect(
            Rect3::new(
                self.bounds().pos + Pt3::new(PAD, PAD, 0.0),
                (port_size - PAD * 2.0).into(),
            ),
            [1.0, 1.0, 1.0],
        );
        ctx.draw_rect(
            Rect3::new(
                self.bounds().pos + Pt3::new(PAD + BORDER_SIZE, PAD + BORDER_SIZE, 0.0),
                (port_size - PAD * 2.0 - BORDER_SIZE * 2.0).into(),
            ),
            [0.0, 0.0, 0.5],
        );
        ctx.draw_text(
            self.backend.label(),
            self.bounds().pos + Pt3::new(20.0, 0.0, 0.0),
            [1.0, 1.0, 1.0],
        );
    }
    fn handle(&mut self, event: &Event) {
        match event.data {
            EventData::Click(pos, button, state) => {
                if event.focus && state == ButtonState::Pressed && button == MouseButton::Left
                    && self.bounds().flatten().drop_z().intersect(pos)
                {
                    let ctx = self.jack_ctx
                        .upgrade()
                        .expect("no events expected during shutdown");
                    let mut in_progress = ctx.in_progress.borrow_mut();
                    let mut connection = self.connection.borrow_mut();
                    if let Some((ref mut weak_in_progress, ref mut endpoint)) = in_progress
                        .as_mut()
                        .and_then(|wip| wip.upgrade().map(|ep| (wip, ep)))
                    {
                        if !Rc::ptr_eq(endpoint, self) {
                            // connection in progress:
                            // click establishes new connection

                            // signal disconnect to backend
                            if connection.is_connected() {
                                self.backend.disconnect();
                            }
                            // update model
                            connection.disconnect();
                            *connection = Connection::Tail {
                                endpoint: weak_in_progress.clone(),
                            };
                            *endpoint.connection.borrow_mut() = Connection::Head {
                                endpoint: Rc::downgrade(self),
                            };
                            *in_progress = None;
                            // signal connect to backend
                            self.backend.connect(&endpoint.backend);
                        }
                    } else {
                        // no connection in progress:
                        // begin connecting

                        // signal disconnect to backend
                        if connection.is_connected() {
                            self.backend.disconnect();
                        }
                        // update model
                        connection.disconnect();
                        *connection = Connection::Floating {
                            pos: pos + self.origin().drop_z(),
                        };
                        *in_progress = Some(Rc::downgrade(self));
                    }
                }
            }
            EventData::MouseMove(mouse_pos) => match *self.connection.borrow_mut() {
                Connection::Floating {
                    ref mut pos,
                } => {
                    *pos = mouse_pos + self.origin().drop_z();
                }
                _ => {}
            },
        }
    }
}

/// a Jack is unaware of other nearby jacks it can connect to
/// so the JackContext manages establishment of connections between jacks
/// (within a specific context)
pub struct JackContext<T: JackBackend> {
    bounds: Cell<Box3>,
    jacks: RefCell<Vec<Weak<Jack<T>>>>,
    in_progress: RefCell<Option<Weak<Jack<T>>>>,
}

impl<T: JackBackend> JackContext<T> {
    pub fn new(bounds: Box3) -> Rc<JackContext<T>> {
        Rc::new(JackContext {
            bounds: Cell::new(bounds),
            jacks: RefCell::new(Vec::new()),
            in_progress: RefCell::new(None),
        })
    }
    pub fn new_jack(self: &Rc<JackContext<T>>, backend: T, bounds: Box3, origin: Pt3) -> Rc<Jack<T>> {
        let jack = Rc::new(Jack::new(&self, backend, bounds, origin));
        let mut jacks = self.jacks.borrow_mut();
        weak_cleanup(&mut jacks);
        jacks.push(Rc::downgrade(&jack));
        jack
    }
}

/// Drop dropped Weak Ts
fn weak_cleanup<T>(vec: &mut Vec<Weak<T>>) {
    vec.retain(|x| x.upgrade().is_some());
}

/// the wires fill space outside of the modules, so they are rendered by the context
impl<T: JackBackend> GuiComponent for Rc<JackContext<T>> {
    fn set_bounds(&mut self, bounds: Box3) {
        self.bounds.set(bounds);
    }
    fn bounds(&self) -> Box3 {
        self.bounds.get()
    }
    fn intersect(&self, pos: Pt2) -> bool {
        self.bounds().flatten().drop_z().intersect(pos)
    }
    fn render(&mut self, device: &mut gl::Device, ctx: &mut RenderContext) {
        let jacks = self.jacks.borrow();
        for jack in jacks.iter() {
            if let Some(jack) = jack.upgrade() {
                match *jack.connection.borrow() {
                    Connection::Head {
                        ref endpoint,
                    } => {
                        if let Some(endpoint) = endpoint.upgrade() {
                            ctx.draw_pipe(&[
                                jack.connection_point().drop_z().with_z(0.0),
                                endpoint.connection_point().drop_z().with_z(0.0),
                            ]);
                        }
                    }
                    Connection::Floating {
                        pos,
                    } => {
                        ctx.draw_pipe(&[
                            jack.connection_point().drop_z().with_z(0.0),
                            pos.with_z(0.0),
                        ]);
                    }
                    _ => {}
                }
            }
        }
    }
    fn handle(&mut self, event: &Event) {}
}
<|endoftext|>


<commit_before>use std::io::{BufRead, ErrorKind, Result, Write};

/// Extends any type that implements BufRead with a stream_until_token() function.
pub trait BufReadExt: BufRead {
    /// Streams all bytes to `out` until the `token` delimiter is reached.
    ///
    /// This function will continue to read (and stream) bytes from the underlying stream until the
    /// token or end-of-file byte is found. Once found, all bytes up to the token (if found) will
    /// have been streamed to `out` and this input stream will advance past the token (the token
    /// will be discarded).
    ///
    /// This function will return `Ok(n)` where `n` is the number of bytes which were read,
    /// including the token if it was found. If the token was not found, it will still return
    /// `Ok(n)`.
    ///
    /// # Errors
    ///
    /// This function will ignore all instances of `ErrorKind::Interrupted` and will otherwise
    /// return any errors returned by `fill_buf`.
    fn stream_until_token<W: Write>(&mut self, token: &[u8], out: &mut W) -> Result<usize> {
        stream_until_token(self, token, out)
    }
}

// Implement BufReadExt for everything that implements BufRead.
impl<T: BufRead> BufReadExt for T { }

fn stream_until_token<R: BufRead + ?Sized, W: Write>(stream: &mut R, token: &[u8], mut out: &mut W)
                                                     -> Result<usize> {
    let mut read = 0;
    // Represents the size of a token prefix found at the end of a buffer, usually 0. If not 0, the
    // beginning of the next buffer is checked for the suffix to find matches that straddle two
    // buffers.
    let mut partial: usize = 0;

    loop {
        let (found, used) = {
            let available = match stream.fill_buf() {
                Ok(n) => n,
                Err(ref err) if err.kind() == ErrorKind::Interrupted => continue,
                Err(err) => return Err(err)
            };

            // If last buffer ended in a token prefix, check if this one starts with the matching
            // suffix.
            if partial > 0 && available[..token.len() - partial] == token[partial..] {
                (true, token.len() - partial)
            } else {
                if partial > 0 {
                    // Last buffer ended in a token prefix, but it didn't pan out, so we need to
                    // push it along.
                    try!( out.write_all(&token[..partial]) );
                }

                let index = available
                    .windows(token.len())
                    .enumerate()
                    .filter(|&(_, t)| t == token)
                    .map(|(i, _)| i)
                    .next();

                // Search for the token.
                match index {
                    Some(index) => {
                        try!(out.write_all(&available[..index]));
                        (true, index + token.len())
                    },
                    None => {
                        // Check for partial matches at the end of the buffer
                        let mut window = token.len() - 1;
                        if available.len() < window {
                            window = available.len();
                        }

                        partial = (1..window+1)
                            .rev()
                            .filter(|&w| token[..w] == available[available.len() - w..])
                            .next()
                            .unwrap_or(0);

                        // Push all except the partial token at the end (if any)
                        try!(out.write_all(&available[..available.len()-partial]));
                        // Mark it all as consumed.
                        (false, available.len())
                    }
                }
            }
        };

        stream.consume(used);
        read += used;

        if found || used == 0 {
            break;
        }
    }

    Ok(read)
}

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

    use std::io::{BufReader, Cursor};

    #[test]
    fn stream_until_token() {
        let mut buf = Cursor::new(&b"123456"[..]);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"78", &mut result).unwrap(), 6);
        assert_eq!(result, b"123456");
        let mut buf = Cursor::new(&b"12345678"[..]);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"34", &mut result).unwrap(), 4);
        assert_eq!(result, b"12");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"78", &mut result).unwrap(), 4);
        assert_eq!(result, b"56");

        let mut buf = Cursor::new(&b"bananas for nana"[..]);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 5);
        assert_eq!(result, b"ba");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 10);
        assert_eq!(result, b"as for ");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 1);
        assert_eq!(result, b"a");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 0);
        assert_eq!(result, b"");
    }

    #[test]
    fn stream_until_token_straddle_test() {
        let cursor = Cursor::new(&b"12345TOKEN345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 10);
        assert_eq!(result, b"12345");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 6);
        assert_eq!(result, b"345678");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 0);
        assert_eq!(result, b"");

        let cursor = Cursor::new(&b"12345TOKE23456781TOKEN78"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 22);
        assert_eq!(result, b"12345TOKE23456781");
    }

    #[test]
    fn stream_until_token_large_token_test() {
        let cursor = Cursor::new(&b"IAMALARGETOKEN7812345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"IAMALARGETOKEN", &mut v).unwrap(), 14);
        assert_eq!(v, b"");
        assert_eq!(buf.stream_until_token(b"IAMALARGETOKEN", &mut v).unwrap(), 10);
        assert_eq!(v, b"7812345678");

        let cursor = Cursor::new(&b"0IAMALARGERTOKEN12345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"IAMALARGERTOKEN", &mut v).unwrap(), 16);
        assert_eq!(v, b"0");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"IAMALARGERTOKEN", &mut v).unwrap(), 8);
        assert_eq!(v, b"12345678");
    }
}
<commit_msg>rename a local variable `available` to `buffer`<commit_after>use std::io::{BufRead, ErrorKind, Result, Write};

/// Extends any type that implements BufRead with a stream_until_token() function.
pub trait BufReadExt: BufRead {
    /// Streams all bytes to `out` until the `token` delimiter is reached.
    ///
    /// This function will continue to read (and stream) bytes from the underlying stream until the
    /// token or end-of-file byte is found. Once found, all bytes up to the token (if found) will
    /// have been streamed to `out` and this input stream will advance past the token (the token
    /// will be discarded).
    ///
    /// This function will return `Ok(n)` where `n` is the number of bytes which were read,
    /// including the token if it was found. If the token was not found, it will still return
    /// `Ok(n)`.
    ///
    /// # Errors
    ///
    /// This function will ignore all instances of `ErrorKind::Interrupted` and will otherwise
    /// return any errors returned by `fill_buf`.
    fn stream_until_token<W: Write>(&mut self, token: &[u8], out: &mut W) -> Result<usize> {
        stream_until_token(self, token, out)
    }
}

// Implement BufReadExt for everything that implements BufRead.
impl<T: BufRead> BufReadExt for T { }

fn stream_until_token<R: BufRead + ?Sized, W: Write>(stream: &mut R, token: &[u8], mut out: &mut W)
                                                     -> Result<usize> {
    let mut read = 0;
    // Represents the size of a token prefix found at the end of a buffer, usually 0. If not 0, the
    // beginning of the next buffer is checked for the suffix to find matches that straddle two
    // buffers.
    let mut partial: usize = 0;

    loop {
        let (found, used) = {
            let buffer = match stream.fill_buf() {
                Ok(n) => n,
                Err(ref err) if err.kind() == ErrorKind::Interrupted => continue,
                Err(err) => return Err(err)
            };

            // If last buffer ended in a token prefix, check if this one starts with the matching
            // suffix.
            if partial > 0 && buffer[..token.len() - partial] == token[partial..] {
                (true, token.len() - partial)
            } else {
                if partial > 0 {
                    // Last buffer ended in a token prefix, but it didn't pan out, so we need to
                    // push it along.
                    try!( out.write_all(&token[..partial]) );
                }

                let index = buffer
                    .windows(token.len())
                    .enumerate()
                    .filter(|&(_, t)| t == token)
                    .map(|(i, _)| i)
                    .next();

                // Search for the token.
                match index {
                    Some(index) => {
                        try!(out.write_all(&buffer[..index]));
                        (true, index + token.len())
                    },
                    None => {
                        // Check for partial matches at the end of the buffer
                        let mut window = token.len() - 1;
                        if buffer.len() < window {
                            window = buffer.len();
                        }

                        partial = (1..window+1)
                            .rev()
                            .filter(|&w| token[..w] == buffer[buffer.len() - w..])
                            .next()
                            .unwrap_or(0);

                        // Push all except the partial token at the end (if any)
                        try!(out.write_all(&buffer[..buffer.len()-partial]));
                        // Mark it all as consumed.
                        (false, buffer.len())
                    }
                }
            }
        };

        stream.consume(used);
        read += used;

        if found || used == 0 {
            break;
        }
    }

    Ok(read)
}

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

    use std::io::{BufReader, Cursor};

    #[test]
    fn stream_until_token() {
        let mut buf = Cursor::new(&b"123456"[..]);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"78", &mut result).unwrap(), 6);
        assert_eq!(result, b"123456");
        let mut buf = Cursor::new(&b"12345678"[..]);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"34", &mut result).unwrap(), 4);
        assert_eq!(result, b"12");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"78", &mut result).unwrap(), 4);
        assert_eq!(result, b"56");

        let mut buf = Cursor::new(&b"bananas for nana"[..]);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 5);
        assert_eq!(result, b"ba");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 10);
        assert_eq!(result, b"as for ");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 1);
        assert_eq!(result, b"a");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"nan", &mut result).unwrap(), 0);
        assert_eq!(result, b"");
    }

    #[test]
    fn stream_until_token_straddle_test() {
        let cursor = Cursor::new(&b"12345TOKEN345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 10);
        assert_eq!(result, b"12345");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 6);
        assert_eq!(result, b"345678");
        result.truncate(0);
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 0);
        assert_eq!(result, b"");

        let cursor = Cursor::new(&b"12345TOKE23456781TOKEN78"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut result: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"TOKEN", &mut result).unwrap(), 22);
        assert_eq!(result, b"12345TOKE23456781");
    }

    #[test]
    fn stream_until_token_large_token_test() {
        let cursor = Cursor::new(&b"IAMALARGETOKEN7812345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"IAMALARGETOKEN", &mut v).unwrap(), 14);
        assert_eq!(v, b"");
        assert_eq!(buf.stream_until_token(b"IAMALARGETOKEN", &mut v).unwrap(), 10);
        assert_eq!(v, b"7812345678");

        let cursor = Cursor::new(&b"0IAMALARGERTOKEN12345678"[..]);
        let mut buf = BufReader::with_capacity(8, cursor);
        let mut v: Vec<u8> = Vec::new();
        assert_eq!(buf.stream_until_token(b"IAMALARGERTOKEN", &mut v).unwrap(), 16);
        assert_eq!(v, b"0");
        v.truncate(0);
        assert_eq!(buf.stream_until_token(b"IAMALARGERTOKEN", &mut v).unwrap(), 8);
        assert_eq!(v, b"12345678");
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, 2016 Mark Lee
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! A cryptographic hash digest generator dependent upon `OpenSSL`.

#![warn(missing_docs)]

use openssl::hash;
use std::io;
use super::Algorithm;

/// Generator of digests using a cryptographic hash function.
///
/// # Examples
///
/// ```rust
/// use crypto_hash::{Algorithm, Hasher};
/// use std::io::Write;
///
/// let mut hasher = Hasher::new(Algorithm::SHA256);
/// hasher.write_all(b"crypto");
/// hasher.write_all(b"-");
/// hasher.write_all(b"hash");
/// let result = hasher.finish();
/// let expected =
///     b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'"
///     .to_vec();
/// assert_eq!(expected, result)
/// ```
pub struct Hasher(hash::Hasher);

impl Hasher {
    /// Create a new `Hasher` for the given `Algorithm`.
    pub fn new(algorithm: Algorithm) -> Hasher {
        let hash_type = match algorithm {
            Algorithm::MD5 => hash::MessageDigest::md5(),
            Algorithm::SHA1 => hash::MessageDigest::sha1(),
            Algorithm::SHA256 => hash::MessageDigest::sha256(),
            Algorithm::SHA512 => hash::MessageDigest::sha512(),
        };

        match hash::Hasher::new(hash_type) {
            Ok(hasher) => Hasher(hasher),
            Err(error_stack) => panic!("OpenSSL error(s): {}", error_stack),
        }
    }

    /// Generate a digest from the data written to the `Hasher`.
    pub fn finish(&mut self) -> Vec<u8> {
        let Hasher(ref mut hasher) = *self;
        match hasher.finish() {
            Ok(digest) => digest,
            Err(error_stack) => panic!("OpenSSL error(s): {}", error_stack),
        }
    }
}

impl io::Write for Hasher {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let Hasher(ref mut hasher) = *self;
        hasher.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        let Hasher(ref mut hasher) = *self;
        hasher.flush()
    }
}
<commit_msg>OpenSSL: use non-deprecated finish method<commit_after>// Copyright (c) 2015, 2016 Mark Lee
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! A cryptographic hash digest generator dependent upon `OpenSSL`.

#![warn(missing_docs)]

use openssl::hash;
use std::io;
use super::Algorithm;

/// Generator of digests using a cryptographic hash function.
///
/// # Examples
///
/// ```rust
/// use crypto_hash::{Algorithm, Hasher};
/// use std::io::Write;
///
/// let mut hasher = Hasher::new(Algorithm::SHA256);
/// hasher.write_all(b"crypto");
/// hasher.write_all(b"-");
/// hasher.write_all(b"hash");
/// let result = hasher.finish();
/// let expected =
///     b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'"
///     .to_vec();
/// assert_eq!(expected, result)
/// ```
pub struct Hasher(hash::Hasher);

impl Hasher {
    /// Create a new `Hasher` for the given `Algorithm`.
    pub fn new(algorithm: Algorithm) -> Hasher {
        let hash_type = match algorithm {
            Algorithm::MD5 => hash::MessageDigest::md5(),
            Algorithm::SHA1 => hash::MessageDigest::sha1(),
            Algorithm::SHA256 => hash::MessageDigest::sha256(),
            Algorithm::SHA512 => hash::MessageDigest::sha512(),
        };

        match hash::Hasher::new(hash_type) {
            Ok(hasher) => Hasher(hasher),
            Err(error_stack) => panic!("OpenSSL error(s): {}", error_stack),
        }
    }

    /// Generate a digest from the data written to the `Hasher`.
    pub fn finish(&mut self) -> Vec<u8> {
        let Hasher(ref mut hasher) = *self;
        match hasher.finish2() {
            Ok(digest) => digest.to_vec(),
            Err(error_stack) => panic!("OpenSSL error(s): {}", error_stack),
        }
    }
}

impl io::Write for Hasher {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let Hasher(ref mut hasher) = *self;
        hasher.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        let Hasher(ref mut hasher) = *self;
        hasher.flush()
    }
}
<|endoftext|>


<commit_before>//! byt - io
//!
//! Implements a piece table to abstract over accessing and
//! modifying a file on disk.

// EXTERNS

// LIBRARY INCLUDES
use std::fmt;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::Empty;
use std::io::BufReader;
use std::io::Read;
use std::io;

// SUBMODULES

// LOCAL INCLUDES

#[derive(Debug, Copy, Clone, PartialEq)]
enum SourceFile {
    /// The original file on disk.
    Original,
    /// The append file, held in memory.
    Append
}

/// A Piece stores some information about a part of the
/// modified file.
#[derive(Clone)]
struct Piece {
    /// The file this piece refers to.
    file : SourceFile,
    /// The offset (in bytes) of the text in this Piece in its file.
    file_offset : u32,
    /// The length of the text in this Piece.
    length : u32,
    /// The logical offset of the Piece.
    logical_offset : u32,
}

impl fmt::Display for Piece {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}:{} ({}){})", self.file, self.file_offset, self.logical_offset, self.length)
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Operation {
    Insert,
    Delete
}

/// Records a particular modification of the text.
struct Action {
    op     : Operation,
    offset : u32,
    pieces : Vec<Piece>,
    length : u32
}

/// Implements logical operations on a file that are not written
/// until asked to.
pub struct PieceFile {
    /// Stores all mutation operations of the file so that we can
    /// undo.
    actions : Vec<Action>,
    /// The in-memory append string. All edits will refer to bytes
    /// stored here.
    append_file : String,
    /// The total size (in bytes) of the PieceFile.
    length : u32,
    /// The path of the file this PieceFile refers to.
    path : String,
    /// Stores all current Pieces.
    piece_table : Vec<Piece>,
    /// The seekable file reader.
    reader : Option<BufReader<File>>,
}

impl PieceFile {
    // #################################
    // P R I V A T E  F U N C T I O N S
    // #################################
    /// Get a Piece at a particular offset.
    fn get_at_offset(&self, offset : u32) -> Option<usize> {
        let mut logical_length = 0;

        // This has to be O(N) for the time being unless we want
        // to update all logical offsets when the table changes.
        // On modern hardware this will hardly be a bottleneck,
        // but we'll see.
        for index in 0..self.piece_table.len() {
            let piece = &self.piece_table[index];
            logical_length += piece.length;

            if offset > logical_length {
                continue;
            }

            return Some(index);
        }

        None
    }

    // ###############################
    // P U B L I C  F U N C T I O N S
    // ###############################
    /// Open a new PieceFile. If the file doesn't exist, it is created.
    pub fn open(path : String) -> io::Result<PieceFile> {
        let file = OpenOptions::new()
            .read(true)
            .open(path.clone()).unwrap();

        // Get the length of the file to initialize the first Piece
        let size = file.metadata().unwrap().len() as u32;

        let mut piece_file = PieceFile {
            actions     : Vec::new(),
            append_file : String::new(),
            length      : size,
            path,
            piece_table : Vec::new(),
            reader      : Some(BufReader::new(file)),
        };

        piece_file.piece_table.push(Piece {
            file : SourceFile::Original,
            file_offset : 0,
            length : size as u32,
            logical_offset : 0,
        });

        Ok(piece_file)
    }

    /// Create a new empty PieceFile.
    pub fn empty() -> io::Result<PieceFile> {
        let mut piece_file = PieceFile {
            actions     : Vec::new(),
            append_file : String::new(),
            length      : 0,
            path        : String::from(""),
            piece_table : Vec::new(),
            reader      : None,
        };

        piece_file.piece_table.push(Piece {
            file : SourceFile::Append,
            file_offset : 0,
            length : 0,
            logical_offset : 0,
        });

        Ok(piece_file)
    }

    /// Insert some text.
    pub fn insert(&mut self, text : &str, offset : u32) {
        let length = text.len() as u32;
        let append_offset = self.append_file.len() as u32;

        self.append_file += text;
        self.length      += length;

        let mut piece = Piece {
            file   : SourceFile::Append,
            file_offset : append_offset,
            logical_offset : 0, // Unknown right now
            length,
        };

        let action = Action {
            op     : Operation::Insert,
            pieces : Vec::new(),
            offset,
            length,
        };

        self.actions.push(action);

        // There are edge cases if you do an insert
        // at the beginning or end of the file.
        if offset == 0 {
            self.piece_table.insert(0, piece);
            return;
        }
        else if offset + length == self.length {
            piece.logical_offset = self.length - length;
            self.piece_table.push(piece);
            return;
        }

        // The insertion may create as many as three pieces. It can
        // split a piece that already exists into two parts and then
        // goes in between them.
        let split_index = match self.get_at_offset(offset) {
            Some(v) => v,
            None => return // TODO: Handle this better
        };
        let split_piece = self.piece_table.remove(split_index);

        let lower_size  = offset - split_piece.logical_offset;
        let upper_size  = (split_piece.logical_offset + split_piece.length) - offset;

        if upper_size > 0 {
            self.piece_table.insert(split_index, Piece {
                file           : split_piece.file,
                file_offset    : split_piece.file_offset + lower_size,
                length         : upper_size,
                logical_offset : split_piece.logical_offset + lower_size + length,
            });
        }

        self.piece_table.insert(split_index, piece);

        if lower_size > 0 {
            self.piece_table.insert(split_index, Piece {
                file           : split_piece.file,
                file_offset    : split_piece.file_offset,
                length         : lower_size,
                logical_offset : split_piece.logical_offset,
            });
        }
    }

    /// Delete some text.
    pub fn delete(&mut self, offset : u32, length : u32) {
        let start_offset = offset;
        let end_offset   = offset + length;
        let start_index  = self.get_at_offset(start_offset).unwrap();
        let end_index    = self.get_at_offset(end_offset).unwrap();
        let delete_size  = end_index - start_index;
        let num_pieces   = (end_index - start_index) + 1;

        let mut action = Action {
            length,
            offset,
            op     : Operation::Delete,
            pieces : Vec::new()
        };

        // Deletes can affect multiple pieces if the user wants to delete
        // across piece boundaries. We have to start at the bottom index
        // and move up.
        for index in start_index..end_index {
            let mut piece          = &self.piece_table[index];
            let piece_start_offset = piece.logical_offset;
            let piece_end_offset   = piece.logical_offset + piece.length;

            // Edge case : delete is embedded WITHIN a single piece
            if start_offset > piece_start_offset && end_offset < piece_end_offset {
                self.piece_table.remove(index);
                let upper_size = piece_end_offset - end_offset;
                let lower_size = start_offset - piece_start_offset;

                action.pieces.push(Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + (start_offset - piece.logical_offset),
                    length         : delete_size,
                    logical_offset : start_offset,
                });

                // We insert the upper part first
                self.piece_table.insert(index, Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size + delete_size,
                    length         : upper_size,
                    logical_offset : start_offset,
                });
                // Then the lower part
                self.piece_table.insert(index, Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset,
                    length         : lower_size,
                    logical_offset : piece.logical_offset,
                });

                return
            }
        }
    }
}

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

    #[test]
    fn it_inserts() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 1);

        file.insert("foo", 0);
        file.insert("bar", 0);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);

        let first_element  = &piece_table[0];
        let second_element = &piece_table[1];

        assert_eq!(first_element.file_offset, 3);
        assert_eq!(first_element.length, 3);

        assert_eq!(second_element.file_offset, 0);
        assert_eq!(second_element.length, 3);

        let action = &file.actions[0];
        assert_eq!(action.op, Operation::Insert);

        // TODO: when read() is implemented check that this says "barfoo"
    }
}
<commit_msg>fix(PieceFile): small bug fixes to pass tests<commit_after>//! byt - io
//!
//! Implements a piece table to abstract over accessing and
//! modifying a file on disk.

// TODO: convert u32 to usize

// EXTERNS

// LIBRARY INCLUDES
use std::fmt;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::Empty;
use std::io::BufReader;
use std::io::Read;
use std::io;

// SUBMODULES

// LOCAL INCLUDES

#[derive(Debug, Copy, Clone, PartialEq)]
enum SourceFile {
    /// The original file on disk.
    Original,
    /// The append file, held in memory.
    Append
}

/// A Piece stores some information about a part of the
/// modified file.
#[derive(Clone)]
struct Piece {
    /// The file this piece refers to.
    file : SourceFile,
    /// The offset (in bytes) of the text in this Piece in its file.
    file_offset : u32,
    /// The length of the text in this Piece.
    length : u32,
    /// The logical offset of the Piece.
    logical_offset : u32,
}

impl fmt::Display for Piece {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}:{} ({}:{})", self.file, self.file_offset, self.logical_offset, self.length)
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum Operation {
    Insert,
    Delete
}

/// Records a particular modification of the text.
struct Action {
    op     : Operation,
    offset : u32,
    pieces : Vec<Piece>,
    length : u32
}

/// Implements logical operations on a file that are not written
/// until asked to.
pub struct PieceFile {
    /// Stores all mutation operations of the file so that we can
    /// undo.
    actions : Vec<Action>,
    /// The in-memory append string. All edits will refer to bytes
    /// stored here.
    append_file : String,
    /// The total size (in bytes) of the PieceFile.
    length : u32,
    /// The path of the file this PieceFile refers to.
    path : String,
    /// Stores all current Pieces.
    piece_table : Vec<Piece>,
    /// The seekable file reader.
    reader : Option<BufReader<File>>,
}

impl PieceFile {
    // #################################
    // P R I V A T E  F U N C T I O N S
    // #################################
    /// Get a Piece at a particular offset.
    fn get_at_offset(&self, offset : u32) -> Option<usize> {
        let mut logical_length = 0;

        // This has to be O(N) for the time being unless we want
        // to update all logical offsets when the table changes.
        // On modern hardware this will hardly be a bottleneck,
        // but we'll see.
        for index in 0..self.piece_table.len() {
            let piece = &self.piece_table[index];
            logical_length += piece.length;

            if offset > logical_length {
                continue;
            }

            return Some(index);
        }

        None
    }

    /// Update the logical offsets starting at a certain index.
    fn update_offsets(&mut self, start_index : usize) {
        // Don't do anything if this is the last index
        if start_index == self.piece_table.len() - 1 {
            return;
        }

        let mut offset = self.piece_table[start_index].logical_offset +
                         self.piece_table[start_index].length;

        for index in start_index + 1 .. self.piece_table.len() {
            let piece = &mut self.piece_table[index];
            piece.logical_offset = offset;
            offset += piece.length;
        }
    }

    // ###############################
    // P U B L I C  F U N C T I O N S
    // ###############################
    /// Open a new PieceFile. If the file doesn't exist, it is created.
    pub fn open(path : String) -> io::Result<PieceFile> {
        let file = OpenOptions::new()
            .read(true)
            .open(path.clone()).unwrap();

        // Get the length of the file to initialize the first Piece
        let size = file.metadata().unwrap().len() as u32;

        let mut piece_file = PieceFile {
            actions     : Vec::new(),
            append_file : String::new(),
            length      : size,
            path,
            piece_table : Vec::new(),
            reader      : Some(BufReader::new(file)),
        };

        piece_file.piece_table.push(Piece {
            file : SourceFile::Original,
            file_offset : 0,
            length : size as u32,
            logical_offset : 0,
        });

        Ok(piece_file)
    }

    /// Create a new empty PieceFile.
    pub fn empty() -> io::Result<PieceFile> {
        let mut piece_file = PieceFile {
            actions     : Vec::new(),
            append_file : String::new(),
            length      : 0,
            path        : String::from(""),
            piece_table : Vec::new(),
            reader      : None,
        };

        Ok(piece_file)
    }

    /// Insert some text.
    pub fn insert(&mut self, text : &str, offset : u32) {
        let length = text.len() as u32;
        let append_offset = self.append_file.len() as u32;

        self.append_file += text;
        self.length      += length;

        let mut piece = Piece {
            file   : SourceFile::Append,
            file_offset : append_offset,
            logical_offset : 0, // Unknown right now
            length,
        };

        let action = Action {
            op     : Operation::Insert,
            pieces : Vec::new(),
            offset,
            length,
        };

        self.actions.push(action);

        // There are edge cases if you do an insert
        // at the beginning or end of the file.
        if offset == 0 {
            self.piece_table.insert(0, piece);
            self.update_offsets(0);
            return;
        }
        else if offset + length == self.length {
            piece.logical_offset = self.length - length;
            self.piece_table.push(piece);
            // No need to update offsets, this is the last piece
            return;
        }

        // The insertion may create as many as three pieces. It can
        // split a piece that already exists into two parts and then
        // goes in between them.
        let split_index = match self.get_at_offset(offset) {
            Some(v) => v,
            None => return // TODO: Handle this better
        };
        let split_piece = self.piece_table.remove(split_index);

        let lower_size  = offset - split_piece.logical_offset;
        let upper_size  = (split_piece.logical_offset + split_piece.length) - offset;

        if upper_size > 0 {
            self.piece_table.insert(split_index, Piece {
                file           : split_piece.file,
                file_offset    : split_piece.file_offset + lower_size,
                length         : upper_size,
                logical_offset : split_piece.logical_offset + lower_size + length,
            });
        }

        self.piece_table.insert(split_index, piece);

        if lower_size > 0 {
            self.piece_table.insert(split_index, Piece {
                file           : split_piece.file,
                file_offset    : split_piece.file_offset,
                length         : lower_size,
                logical_offset : split_piece.logical_offset,
            });
        }
        self.update_offsets(split_index);
    }

    /// Delete some text.
    pub fn delete(&mut self, offset : u32, length : u32) {
        let start_offset = offset;
        let end_offset   = offset + length;
        let start_index  = self.get_at_offset(start_offset).unwrap();
        let end_index    = self.get_at_offset(end_offset).unwrap();
        let delete_size  = (end_index - start_index) as u32;
        let num_pieces   = (end_index - start_index) + 1;

        let mut action = Action {
            length,
            offset,
            op     : Operation::Delete,
            pieces : Vec::new()
        };

        // Deletes can affect multiple pieces if the user wants to delete
        // across piece boundaries. We have to start at the bottom index
        // and move up. The code below doesn't result in a net positive number
        // of pieces in the piece table. We do any deletion necessary in a second
        // pass.
        for index in start_index .. end_index + 1 {
            let piece              = self.piece_table[index].clone();
            let piece_start_offset = piece.logical_offset;
            let piece_end_offset   = piece.logical_offset + piece.length;

            // Edge case : delete is embedded WITHIN a single piece
            if start_offset > piece_start_offset && end_offset < piece_end_offset {
                self.piece_table.remove(index);
                let upper_size = piece_end_offset - end_offset;
                let lower_size = start_offset - piece_start_offset;

                action.pieces.push(Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size,
                    length         : delete_size,
                    logical_offset : start_offset,
                });

                // We insert the upper part first
                self.piece_table.insert(index, Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size + delete_size,
                    length         : upper_size,
                    logical_offset : start_offset,
                });

                // Then the lower part
                self.piece_table.insert(index, Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset,
                    length         : lower_size,
                    logical_offset : piece.logical_offset,
                });
                break
            }

            // The deletion area starts in a piece and goes on to another
            if start_offset < piece_end_offset && end_offset >= piece_end_offset {
                let piece      = &mut self.piece_table[index];
                let upper_size = piece_end_offset - start_offset;
                let lower_size = start_offset - piece_start_offset;

                action.pieces.push(Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size,
                    length         : upper_size,
                    logical_offset : piece_start_offset + lower_size,
                });

                piece.length = lower_size;
                continue;
            }

            // The deletion area finishes in this piece
            if start_offset < piece_start_offset && end_offset >= piece_start_offset {
                let piece      = &mut self.piece_table[index];
                let upper_size = piece_end_offset - end_offset;
                let lower_size = end_offset - piece_start_offset;

                action.pieces.push(Piece {
                    file           : piece.file,
                    file_offset    : piece.file_offset + lower_size,
                    length         : lower_size,
                    logical_offset : piece_start_offset - lower_size,
                });

                piece.length = upper_size;
                continue;
            }

            if start_offset <= piece_start_offset && end_offset >= piece_end_offset {
                let piece = &mut self.piece_table[index];
                action.pieces.push(piece.clone());
                piece.length = 0;
            }
        }

        // It's possible that we left zero-length pieces above. We should delete them.
        self.piece_table.retain(|ref v| v.length > 0);

        self.update_offsets(start_index);
    }
}

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

    #[test]
    fn it_inserts() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        file.insert("foo", 0);
        file.insert("bar", 0);

        assert_eq!(file.length, 6);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);

        let first_element  = &piece_table[0];
        let second_element = &piece_table[1];

        assert_eq!(first_element.file_offset, 3);
        assert_eq!(first_element.logical_offset, 0);
        assert_eq!(first_element.length, 3);

        assert_eq!(second_element.file_offset, 0);
        assert_eq!(second_element.logical_offset, 3);
        assert_eq!(second_element.length, 3);

        let action = &file.actions[0];
        assert_eq!(action.op, Operation::Insert);

        // TODO: Check the action's steps
    }

    #[test]
    fn it_deletes_inside_piece() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        // Test a delete that occurs inside a piece
        file.insert("foo", 0);
        file.delete(1, 1);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);
        assert_eq!(piece_table[0].length, 1);
        assert_eq!(piece_table[1].length, 1);

        // TODO: check the action's steps
    }

    #[test]
    fn it_deletes_across_two_pieces() {
        let mut file = PieceFile::empty().unwrap();
        assert_eq!(file.piece_table.len(), 0);

        file.insert("bar", 0);
        file.insert("foo", 0);
        file.delete(2,2);

        let piece_table = &file.piece_table;
        assert_eq!(piece_table.len(), 2);
        assert_eq!(piece_table[0].length, 2);
        assert_eq!(piece_table[1].length, 2);

        // TODO: check the action's steps
    }
}
<|endoftext|>


<commit_before>//!
//! A simple demonstration of how to construct and use Canvasses by splitting up the window.
//!

extern crate conrod;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate glutin_window;
extern crate graphics;
extern crate piston;
extern crate piston_window;

use conrod::{CanvasId, Floating, Theme, Widget, WidgetId};
use gfx_device_gl::{CommandBuffer, Resources, Output};
use gfx_graphics::{GfxGraphics, GlyphCache};
use glutin_window::{GlutinWindow, OpenGL};
use graphics::Context;
use piston::window::{WindowSettings, Size};
use piston_window::PistonWindow;
use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc;

type Ui = conrod::Ui<GlyphCache<Resources>>;
type Graphics<'a> = GfxGraphics<'a, Resources, CommandBuffer, Output>;

fn main() {

    // Construct the window.
    let window = {
        let window = GlutinWindow::new(
            OpenGL::_3_2,
            WindowSettings::new("Canvas Demo".to_string(), Size { width: 800, height: 600 })
                .exit_on_esc(true)
        );
        PistonWindow::new(Rc::new(RefCell::new(window)), piston_window::empty_app())
    };

    // Spawn the gfx::factory.
    let mut factory = window.device.borrow().spawn_factory();

    // construct our `Ui`.
    let mut ui = {
        let font_path = Path::new("./assets/NotoSans/NotoSans-Regular.ttf");
        let theme = Theme::default();
        let glyph_cache = GlyphCache::new(&font_path, &mut factory);
        Ui::new(glyph_cache.unwrap(), theme)
    };

    // Poll events from the window.
    for event in window {
        ui.handle_event(&event);
        event.draw_2d(|c, g| draw_ui(&mut ui, c, g));
        ui.glyph_cache.borrow_mut().update(&mut factory);
    }

}

// Draw the Ui.
fn draw_ui<'a>(ui: &mut Ui, c: Context, g: &mut Graphics<'a>) {
    use conrod::color::{blue, light_orange, orange, dark_orange, red, white};
    use conrod::{Button, Colorable, Label, Labelable, Positionable, Sizeable, Split, WidgetMatrix};

    // Construct our Canvas tree.
    Split::new(MASTER).flow_down(&[
        Split::new(HEADER).color(blue()).pad_bottom(20.0),
        Split::new(BODY).length(300.0).flow_right(&[
            Split::new(LEFT_COLUMN).color(light_orange()).pad(20.0),
            Split::new(MIDDLE_COLUMN).color(orange()),
            Split::new(RIGHT_COLUMN).color(dark_orange()).pad(20.0),
        ]),
        Split::new(FOOTER).color(blue())
    ]).set(ui);

    Floating::new()
        .label("Blue")
        .middle_of(LEFT_COLUMN)
        .color(blue())
        .label_color(white())
        .set(FLOATING_A, ui);

    Floating::new()
        .label("Orange")
        .middle_of(RIGHT_COLUMN)
        .color(light_orange())
        .label_color(white())
        .set(FLOATING_B, ui);

    Label::new("Fancy Title").color(light_orange()).font_size(48).middle_of(HEADER).set(TITLE, ui);
    Label::new("Subtitle").color(blue().complement()).mid_bottom_of(HEADER).set(SUBTITLE, ui);

    Label::new("Top Left")
        .color(light_orange().complement())
        .top_left_of(LEFT_COLUMN)
        .set(TOP_LEFT, ui);

    Label::new("Middle")
        .color(orange().complement())
        .middle_of(MIDDLE_COLUMN)
        .set(MIDDLE, ui);

    Label::new("Bottom Right")
        .color(dark_orange().complement())
        .bottom_right_of(RIGHT_COLUMN)
        .set(BOTTOM_RIGHT, ui);

    WidgetMatrix::new(COLS, ROWS)
        .dim(ui.canvas_size(FOOTER))
        .middle_of(FOOTER)
        .each_widget(ui, |ui, n, _col, _row, xy, dim| {
            Button::new()
                .color(blue().with_luminance(n as f32 / (COLS * ROWS) as f32))
                .dim(dim)
                .point(xy)
                .react(|| println!("Hey! {:?}", n))
                .set(BUTTON + n, ui);
        });

    Button::new().color(red()).dimensions(30.0, 30.0).middle_of(FLOATING_A)
        .react(|| println!("Bing!"))
        .set(BING, ui);
    Button::new().color(red()).dimensions(30.0, 30.0).middle_of(FLOATING_B)
        .react(|| println!("Bong!"))
        .set(BONG, ui);

    ui.draw(c, g);
}

// Canvas IDs.
const MASTER: CanvasId = 0;
const HEADER: CanvasId = MASTER + 1;
const BODY: CanvasId = HEADER + 1;
const LEFT_COLUMN: CanvasId = BODY + 1;
const MIDDLE_COLUMN: CanvasId = LEFT_COLUMN + 1;
const RIGHT_COLUMN: CanvasId = MIDDLE_COLUMN + 1;
const FOOTER: CanvasId = RIGHT_COLUMN + 1;
const FLOATING_A: CanvasId = FOOTER + 1;
const FLOATING_B: CanvasId = FLOATING_A + 1;

// Widget IDs.
const TITLE: WidgetId = 0;
const SUBTITLE: WidgetId = TITLE + 1;
const TOP_LEFT: WidgetId = SUBTITLE + 1;
const MIDDLE: WidgetId = TOP_LEFT + 1;
const BOTTOM_RIGHT: WidgetId = MIDDLE + 1;
const BUTTON: WidgetId = BOTTOM_RIGHT + 1;
const ROWS: usize = 5;
const COLS: usize = 24;
const BING: WidgetId = BUTTON + COLS * ROWS;
const BONG: WidgetId = BING + 1;

<commit_msg>Updated example to latest gfx_graphics GlyphCache changes<commit_after>//!
//! A simple demonstration of how to construct and use Canvasses by splitting up the window.
//!

extern crate conrod;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate glutin_window;
extern crate graphics;
extern crate piston;
extern crate piston_window;

use conrod::{CanvasId, Floating, Theme, Widget, WidgetId};
use gfx_device_gl::{CommandBuffer, Factory, Resources, Output};
use gfx_graphics::{GfxGraphics, GlyphCache};
use glutin_window::{GlutinWindow, OpenGL};
use graphics::Context;
use piston::window::{WindowSettings, Size};
use piston_window::PistonWindow;
use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc;

type Ui = conrod::Ui<GlyphCache<Resources, Factory>>;
type Graphics<'a> = GfxGraphics<'a, Resources, CommandBuffer, Output>;

fn main() {

    // Construct the window.
    let window = {
        let window = GlutinWindow::new(
            OpenGL::_3_2,
            WindowSettings::new("Canvas Demo".to_string(), Size { width: 800, height: 600 })
                .exit_on_esc(true)
        );
        PistonWindow::new(Rc::new(RefCell::new(window)), piston_window::empty_app())
    };

    // construct our `Ui`.
    let mut ui = {
        let font_path = Path::new("./assets/NotoSans/NotoSans-Regular.ttf");
        let theme = Theme::default();
        let glyph_cache = GlyphCache::new(&font_path, window.device.borrow().spawn_factory());
        Ui::new(glyph_cache.unwrap(), theme)
    };

    // Poll events from the window.
    for event in window {
        ui.handle_event(&event);
        event.draw_2d(|c, g| draw_ui(&mut ui, c, g));
    }

}

// Draw the Ui.
fn draw_ui<'a>(ui: &mut Ui, c: Context, g: &mut Graphics<'a>) {
    use conrod::color::{blue, light_orange, orange, dark_orange, red, white};
    use conrod::{Button, Colorable, Label, Labelable, Positionable, Sizeable, Split, WidgetMatrix};

    // Construct our Canvas tree.
    Split::new(MASTER).flow_down(&[
        Split::new(HEADER).color(blue()).pad_bottom(20.0),
        Split::new(BODY).length(300.0).flow_right(&[
            Split::new(LEFT_COLUMN).color(light_orange()).pad(20.0),
            Split::new(MIDDLE_COLUMN).color(orange()),
            Split::new(RIGHT_COLUMN).color(dark_orange()).pad(20.0),
        ]),
        Split::new(FOOTER).color(blue())
    ]).set(ui);

    Floating::new()
        .label("Blue")
        .middle_of(LEFT_COLUMN)
        .color(blue())
        .label_color(white())
        .set(FLOATING_A, ui);

    Floating::new()
        .label("Orange")
        .middle_of(RIGHT_COLUMN)
        .color(light_orange())
        .label_color(white())
        .set(FLOATING_B, ui);

    Label::new("Fancy Title").color(light_orange()).font_size(48).middle_of(HEADER).set(TITLE, ui);
    Label::new("Subtitle").color(blue().complement()).mid_bottom_of(HEADER).set(SUBTITLE, ui);

    Label::new("Top Left")
        .color(light_orange().complement())
        .top_left_of(LEFT_COLUMN)
        .set(TOP_LEFT, ui);

    Label::new("Middle")
        .color(orange().complement())
        .middle_of(MIDDLE_COLUMN)
        .set(MIDDLE, ui);

    Label::new("Bottom Right")
        .color(dark_orange().complement())
        .bottom_right_of(RIGHT_COLUMN)
        .set(BOTTOM_RIGHT, ui);

    WidgetMatrix::new(COLS, ROWS)
        .dim(ui.canvas_size(FOOTER))
        .middle_of(FOOTER)
        .each_widget(ui, |ui, n, _col, _row, xy, dim| {
            Button::new()
                .color(blue().with_luminance(n as f32 / (COLS * ROWS) as f32))
                .dim(dim)
                .point(xy)
                .react(|| println!("Hey! {:?}", n))
                .set(BUTTON + n, ui);
        });

    Button::new().color(red()).dimensions(30.0, 30.0).middle_of(FLOATING_A)
        .react(|| println!("Bing!"))
        .set(BING, ui);
    Button::new().color(red()).dimensions(30.0, 30.0).middle_of(FLOATING_B)
        .react(|| println!("Bong!"))
        .set(BONG, ui);

    ui.draw(c, g);
}

// Canvas IDs.
const MASTER: CanvasId = 0;
const HEADER: CanvasId = MASTER + 1;
const BODY: CanvasId = HEADER + 1;
const LEFT_COLUMN: CanvasId = BODY + 1;
const MIDDLE_COLUMN: CanvasId = LEFT_COLUMN + 1;
const RIGHT_COLUMN: CanvasId = MIDDLE_COLUMN + 1;
const FOOTER: CanvasId = RIGHT_COLUMN + 1;
const FLOATING_A: CanvasId = FOOTER + 1;
const FLOATING_B: CanvasId = FLOATING_A + 1;

// Widget IDs.
const TITLE: WidgetId = 0;
const SUBTITLE: WidgetId = TITLE + 1;
const TOP_LEFT: WidgetId = SUBTITLE + 1;
const MIDDLE: WidgetId = TOP_LEFT + 1;
const BOTTOM_RIGHT: WidgetId = MIDDLE + 1;
const BUTTON: WidgetId = BOTTOM_RIGHT + 1;
const ROWS: usize = 5;
const COLS: usize = 24;
const BING: WidgetId = BUTTON + COLS * ROWS;
const BONG: WidgetId = BING + 1;

<|endoftext|>


<commit_before>extern crate jsonwebtoken as jwt;
extern crate rustc_serialize;

use jwt::{encode, decode, Header, Algorithm};
use jwt::errors::{Error};

#[derive(Debug, RustcEncodable, RustcDecodable)]
struct Claims {
    sub: String,
    company: String
}

// Example validation implementation
impl Claims {
    fn is_valid(self) -> bool {
        if self.company != "ACME".to_owned() {
            return false;
        }
        // expiration etc

        true
    }
}

fn main() {
    let my_claims = Claims {
        sub: "b@b.com".to_owned(),
        company: "ACME".to_owned()
    };
    let key = "secret";
    let token = match encode(Header::default(), &my_claims, key.as_ref()) {
        Ok(t) => t,
        Err(_) => panic!() // in practice you would return the error
    };

    println!("{:?}", token);

    let token_data = match decode::<Claims>(&token, key.as_ref(), Algorithm::HS256) {
        Ok(c) => c,
        Err(err) => match err {
            Error::InvalidToken => panic!(), // Example on how to handle a specific error
            _ => panic!()
        }
    };
    println!("{:?}", token_data.claims);
    println!("{:?}", token_data.header);
    println!("{:?}", token_data.claims.is_valid());
}
<commit_msg>Fix example<commit_after>extern crate jsonwebtoken as jwt;
extern crate rustc_serialize;

use jwt::{encode, decode, Header, Algorithm};
use jwt::errors::{Error};

#[derive(Debug, RustcEncodable, RustcDecodable)]
struct Claims {
    sub: String,
    company: String
}

// Example validation implementation
impl Claims {
    fn is_valid(&self) -> bool {
        if self.company != "ACME" {
            return false;
        }
        // expiration etc

        true
    }
}

fn main() {
    let my_claims = Claims {
        sub: "b@b.com".to_owned(),
        company: "ACME".to_owned()
    };
    let key = "secret";
    let token = match encode(Header::default(), &my_claims, key.as_ref()) {
        Ok(t) => t,
        Err(_) => panic!() // in practice you would return the error
    };

    println!("{:?}", token);

    let token_data = match decode::<Claims>(&token, key.as_ref(), Algorithm::HS256) {
        Ok(c) => c,
        Err(err) => match err {
            Error::InvalidToken => panic!(), // Example on how to handle a specific error
            _ => panic!()
        }
    };
    println!("{:?}", token_data.claims);
    println!("{:?}", token_data.header);
    println!("{:?}", token_data.claims.is_valid());
}
<|endoftext|>


<commit_before>use crc32::Crc32 as crc32;
use crc64::Crc64 as crc64;

use std::path::Path;
use std::fs::File;
use std::io::Read;

pub struct Checksum {
    pub crc32: u32,
    pub crc64: u64,
}

pub struct Crc {
    checksum: Checksum,
    path: String,
}

impl Crc {
    pub fn new(filepath: &str) -> Crc {
        let crc = Crc {
            checksum: Checksum {
                crc32: 0x00000000,
                crc64: 0x0000000000000000,
            },
            path: filepath.to_string(),
        };
        crc
    }

    pub fn checksum(&mut self) -> Result<&Checksum, &str> {
        let path = Path::new(&self.path);
        let mut buffer = [0u8; 1_048_576];
        let mut file = match File::open(&path) {
            Ok(file) => file,
            Err(_) => {
                let res: Result<&Checksum, &str> = Err("File Open Error");
                return res;
            }
        };

        let mut c32 = crc32::new();
        let mut c64 = crc64::new();
        while match file.read(&mut buffer) {
            Ok(len) => {
                c32.update(&buffer[0..len]);
                c64.update(&buffer[0..len]);
                len > 0
            }
            Err(_) => {
                let res: Result<&Checksum, &str> = Err("File Read Error");
                return res;
            }
        } {}
        c32.finalize();
        c64.finalize();

        self.checksum.crc32 = c32.getsum();
        self.checksum.crc64 = c64.getsum();
        let res: Result<&Checksum, &str> = Ok(&self.checksum);
        return res;
    }

    pub fn print_checksum(&self) {
        println!("{:X}", self.checksum.crc32);
        println!("{:X}", self.checksum.crc64);
    }
}
<commit_msg>Added test for file checksums<commit_after>use crc32::Crc32 as crc32;
use crc64::Crc64 as crc64;

use std::path::Path;
use std::fs::File;
use std::io::Read;

pub struct Checksum {
    pub crc32: u32,
    pub crc64: u64,
}

pub struct Crc {
    checksum: Checksum,
    path: String,
}

impl Crc {
    pub fn new(filepath: &str) -> Crc {
        let crc = Crc {
            checksum: Checksum {
                crc32: 0x00000000,
                crc64: 0x0000000000000000,
            },
            path: filepath.to_string(),
        };
        crc
    }

    pub fn checksum(&mut self) -> Result<&Checksum, &str> {
        let path = Path::new(&self.path);
        let mut buffer = [0u8; 1_048_576];
        let mut file = match File::open(&path) {
            Ok(file) => file,
            Err(_) => {
                let res: Result<&Checksum, &str> = Err("File Open Error");
                return res;
            }
        };

        let mut c32 = crc32::new();
        let mut c64 = crc64::new();
        while match file.read(&mut buffer) {
            Ok(len) => {
                c32.update(&buffer[0..len]);
                c64.update(&buffer[0..len]);
                len > 0
            }
            Err(_) => {
                let res: Result<&Checksum, &str> = Err("File Read Error");
                return res;
            }
        } {}
        c32.finalize();
        c64.finalize();

        self.checksum.crc32 = c32.getsum();
        self.checksum.crc64 = c64.getsum();
        let res: Result<&Checksum, &str> = Ok(&self.checksum);
        return res;
    }

    pub fn print_checksum(&self) {
        println!("{:X}", self.checksum.crc32);
        println!("{:X}", self.checksum.crc64);
    }

    pub fn getsums(&self) -> &Checksum {
        &self.checksum
    }
}

#[test]
fn crc_test() {
    use std::fs::File;
    use std::fs;

    let file = File::create("foo.txt").unwrap();
    file.set_len(1572864).unwrap();

    let mut crc = Crc::new("foo.txt");
    crc.checksum().unwrap();
    let sums: &Checksum = crc.getsums();

    fs::remove_file("foo.txt").unwrap();

    assert_eq!(sums.crc32,0xAC2C5EE1);
    assert_eq!(sums.crc64,0xD39C35166B57EF79);
}
<|endoftext|>


<commit_before>//! A simple parser for a tiny subset of CSS.
//!
//! To support more CSS syntax, it would probably be easiest to replace this
//! hand-rolled parser with one based on a library or parser generator.

use std::ascii::OwnedAsciiExt; // for `into_ascii_lower`
use std::from_str::FromStr;
use std::num::FromStrRadix;

// Data structures:

#[deriving(Show)]
pub struct Stylesheet {
    pub rules: Vec<Rule>,
}

#[deriving(Show)]
pub struct Rule {
    pub selectors: Vec<Selector>,
    pub declarations: Vec<Declaration>,
}

#[deriving(Show)]
pub enum Selector {
    Simple(SimpleSelector),
}

#[deriving(Show)]
pub struct SimpleSelector {
    pub tag_name: Option<String>,
    pub id: Option<String>,
    pub class: Vec<String>,
}

#[deriving(Show)]
pub struct Declaration {
    pub name: String,
    pub value: Value,
}

#[deriving(Show, Clone, PartialEq)]
pub enum Value {
    Keyword(String),
    Length(f32, Unit),
    Color(u8, u8, u8, u8), // RGBA
}

#[deriving(Show, Clone, PartialEq)]
pub enum Unit {
    Px,
}

pub type Specificity = (uint, uint, uint);

impl Selector {
    pub fn specificity(&self) -> Specificity {
        // http://www.w3.org/TR/selectors/#specificity
        let Simple(ref simple) = *self;
        let a = simple.id.iter().len();
        let b = simple.class.len();
        let c = simple.tag_name.iter().len();
        (a, b, c)
    }
}

impl Value {
    /// Return the size of a length in px, or zero for non-lengths.
    pub fn to_px(&self) -> f32 {
        match *self {
            Length(f, Px) => f,
            _ => 0.0
        }
    }
}

/// Parse a whole CSS stylesheet.
pub fn parse(source: String) -> Stylesheet {
    let mut parser = Parser { pos: 0u, input: source };
    Stylesheet { rules: parser.parse_rules() }
}

struct Parser {
    pos: uint,
    input: String,
}

impl Parser {
    /// Parse a list of rule sets, separated by optional whitespace.
    fn parse_rules(&mut self) -> Vec<Rule> {
        let mut rules = Vec::new();
        loop {
            self.consume_whitespace();
            if self.eof() { break }
            rules.push(self.parse_rule());
        }
        return rules;
    }

    /// Parse a rule set: `<selectors> { <declarations> }`.
    fn parse_rule(&mut self) -> Rule {
        Rule {
            selectors: self.parse_selectors(),
            declarations: self.parse_declarations(),
        }
    }

    /// Parse a comma-separated list of selectors.
    fn parse_selectors(&mut self) -> Vec<Selector> {
        let mut selectors = Vec::new();
        loop {
            selectors.push(Simple(self.parse_simple_selector()));
            self.consume_whitespace();
            match self.next_char() {
                ',' => { self.consume_char(); self.consume_whitespace(); }
                '{' => break,
                c   => panic!("Unexpected character {} in selector list", c)
            }
        }
        // Return selectors with highest specificity first, for use in matching.
        selectors.sort_by(|a,b| b.specificity().cmp(&a.specificity()));
        return selectors;
    }

    /// Parse one simple selector, e.g.: `type#id.class1.class2.class3`
    fn parse_simple_selector(&mut self) -> SimpleSelector {
        let mut selector = SimpleSelector { tag_name: None, id: None, class: Vec::new() };
        while !self.eof() {
            match self.next_char() {
                '#' => {
                    self.consume_char();
                    selector.id = Some(self.parse_identifier());
                }
                '.' => {
                    self.consume_char();
                    selector.class.push(self.parse_identifier());
                }
                '*' => {
                    // universal selector
                    self.consume_char();
                }
                c if valid_identifier_char(c) => {
                    selector.tag_name = Some(self.parse_identifier());
                }
                _ => break
            }
        }
        return selector;
    }

    /// Parse a list of declarations enclosed in `{ ... }`.
    fn parse_declarations(&mut self) -> Vec<Declaration> {
        assert!(self.consume_char() == '{');
        let mut declarations = Vec::new();
        loop {
            self.consume_whitespace();
            if self.next_char() == '}' {
                self.consume_char();
                break;
            }
            declarations.push(self.parse_declaration());
        }
        return declarations;
    }

    /// Parse one `<property>: <value>;` declaration.
    fn parse_declaration(&mut self) -> Declaration {
        let property_name = self.parse_identifier();
        self.consume_whitespace();
        assert!(self.consume_char() == ':')
        self.consume_whitespace();
        let value = self.parse_value();
        self.consume_whitespace();
        assert!(self.consume_char() == ';')

        Declaration {
            name: property_name,
            value: value,
        }
    }

    // Methods for parsing values:

    fn parse_value(&mut self) -> Value {
        match self.next_char() {
            '0'...'9' => self.parse_length(),
            '#' => self.parse_color(),
            _ => Keyword(self.parse_identifier())
        }
    }

    fn parse_length(&mut self) -> Value {
        Length(self.parse_float(), self.parse_unit())
    }

    fn parse_float(&mut self) -> f32 {
        let s = self.consume_while(|c| match c {
            '0'...'9' | '.' => true,
            _ => false
        });
        let f: Option<f32> = FromStr::from_str(s.as_slice());
        f.unwrap()
    }

    fn parse_unit(&mut self) -> Unit {
        match self.parse_identifier().into_ascii_lower().as_slice() {
            "px" => Px,
            _ => panic!("unrecognized unit")
        }
    }

    fn parse_color(&mut self) -> Value {
        assert!(self.consume_char() == '#');
        Color(self.parse_hex_pair(), self.parse_hex_pair(), self.parse_hex_pair(), 255)
    }

    /// Parse two hexadecimal digits.
    fn parse_hex_pair(&mut self) -> u8 {
        let s = self.input.as_slice().slice(self.pos, self.pos + 2);
        self.pos = self.pos + 2;
        FromStrRadix::from_str_radix(s, 0x10).unwrap()
    }

    /// Parse a property name or keyword.
    fn parse_identifier(&mut self) -> String {
        self.consume_while(valid_identifier_char)
    }

    /// Consume and discard zero or more whitespace characters.
    fn consume_whitespace(&mut self) {
        self.consume_while(|c| c.is_whitespace());
    }

    /// Consume characters until `test` returns false.
    fn consume_while(&mut self, test: |char| -> bool) -> String {
        let mut result = String::new();
        while !self.eof() && test(self.next_char()) {
            result.push(self.consume_char());
        }
        return result;
    }

    /// Return the current character, and advance self.pos to the next character.
    fn consume_char(&mut self) -> char {
        let range = self.input.as_slice().char_range_at(self.pos);
        self.pos = range.next;
        return range.ch;
    }

    /// Read the current character without consuming it.
    fn next_char(&self) -> char {
        self.input.as_slice().char_at(self.pos)
    }

    /// Return true if all input is consumed.
    fn eof(&self) -> bool {
        self.pos >= self.input.len()
    }
}

fn valid_identifier_char(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' | '0'...'9' | '-' | '_' => true, // TODO: Include U+00A0 and higher.
        _ => false,
    }
}
<commit_msg>Split color into a separate struct<commit_after>//! A simple parser for a tiny subset of CSS.
//!
//! To support more CSS syntax, it would probably be easiest to replace this
//! hand-rolled parser with one based on a library or parser generator.

use std::ascii::OwnedAsciiExt; // for `into_ascii_lower`
use std::from_str::FromStr;
use std::num::FromStrRadix;

// Data structures:

#[deriving(Show)]
pub struct Stylesheet {
    pub rules: Vec<Rule>,
}

#[deriving(Show)]
pub struct Rule {
    pub selectors: Vec<Selector>,
    pub declarations: Vec<Declaration>,
}

#[deriving(Show)]
pub enum Selector {
    Simple(SimpleSelector),
}

#[deriving(Show)]
pub struct SimpleSelector {
    pub tag_name: Option<String>,
    pub id: Option<String>,
    pub class: Vec<String>,
}

#[deriving(Show)]
pub struct Declaration {
    pub name: String,
    pub value: Value,
}

#[deriving(Show, Clone, PartialEq)]
pub enum Value {
    Keyword(String),
    Length(f32, Unit),
    ColorValue(Color), // RGBA
}

#[deriving(Show, Clone, PartialEq)]
pub enum Unit {
    Px,
}

#[deriving(Show, Clone, PartialEq)]
pub struct Color {
    r: u8,
    g: u8,
    b: u8,
    a: u8,
}

pub type Specificity = (uint, uint, uint);

impl Selector {
    pub fn specificity(&self) -> Specificity {
        // http://www.w3.org/TR/selectors/#specificity
        let Simple(ref simple) = *self;
        let a = simple.id.iter().len();
        let b = simple.class.len();
        let c = simple.tag_name.iter().len();
        (a, b, c)
    }
}

impl Value {
    /// Return the size of a length in px, or zero for non-lengths.
    pub fn to_px(&self) -> f32 {
        match *self {
            Length(f, Px) => f,
            _ => 0.0
        }
    }
}

/// Parse a whole CSS stylesheet.
pub fn parse(source: String) -> Stylesheet {
    let mut parser = Parser { pos: 0u, input: source };
    Stylesheet { rules: parser.parse_rules() }
}

struct Parser {
    pos: uint,
    input: String,
}

impl Parser {
    /// Parse a list of rule sets, separated by optional whitespace.
    fn parse_rules(&mut self) -> Vec<Rule> {
        let mut rules = Vec::new();
        loop {
            self.consume_whitespace();
            if self.eof() { break }
            rules.push(self.parse_rule());
        }
        return rules;
    }

    /// Parse a rule set: `<selectors> { <declarations> }`.
    fn parse_rule(&mut self) -> Rule {
        Rule {
            selectors: self.parse_selectors(),
            declarations: self.parse_declarations(),
        }
    }

    /// Parse a comma-separated list of selectors.
    fn parse_selectors(&mut self) -> Vec<Selector> {
        let mut selectors = Vec::new();
        loop {
            selectors.push(Simple(self.parse_simple_selector()));
            self.consume_whitespace();
            match self.next_char() {
                ',' => { self.consume_char(); self.consume_whitespace(); }
                '{' => break,
                c   => panic!("Unexpected character {} in selector list", c)
            }
        }
        // Return selectors with highest specificity first, for use in matching.
        selectors.sort_by(|a,b| b.specificity().cmp(&a.specificity()));
        return selectors;
    }

    /// Parse one simple selector, e.g.: `type#id.class1.class2.class3`
    fn parse_simple_selector(&mut self) -> SimpleSelector {
        let mut selector = SimpleSelector { tag_name: None, id: None, class: Vec::new() };
        while !self.eof() {
            match self.next_char() {
                '#' => {
                    self.consume_char();
                    selector.id = Some(self.parse_identifier());
                }
                '.' => {
                    self.consume_char();
                    selector.class.push(self.parse_identifier());
                }
                '*' => {
                    // universal selector
                    self.consume_char();
                }
                c if valid_identifier_char(c) => {
                    selector.tag_name = Some(self.parse_identifier());
                }
                _ => break
            }
        }
        return selector;
    }

    /// Parse a list of declarations enclosed in `{ ... }`.
    fn parse_declarations(&mut self) -> Vec<Declaration> {
        assert!(self.consume_char() == '{');
        let mut declarations = Vec::new();
        loop {
            self.consume_whitespace();
            if self.next_char() == '}' {
                self.consume_char();
                break;
            }
            declarations.push(self.parse_declaration());
        }
        return declarations;
    }

    /// Parse one `<property>: <value>;` declaration.
    fn parse_declaration(&mut self) -> Declaration {
        let property_name = self.parse_identifier();
        self.consume_whitespace();
        assert!(self.consume_char() == ':')
        self.consume_whitespace();
        let value = self.parse_value();
        self.consume_whitespace();
        assert!(self.consume_char() == ';')

        Declaration {
            name: property_name,
            value: value,
        }
    }

    // Methods for parsing values:

    fn parse_value(&mut self) -> Value {
        match self.next_char() {
            '0'...'9' => self.parse_length(),
            '#' => self.parse_color(),
            _ => Keyword(self.parse_identifier())
        }
    }

    fn parse_length(&mut self) -> Value {
        Length(self.parse_float(), self.parse_unit())
    }

    fn parse_float(&mut self) -> f32 {
        let s = self.consume_while(|c| match c {
            '0'...'9' | '.' => true,
            _ => false
        });
        let f: Option<f32> = FromStr::from_str(s.as_slice());
        f.unwrap()
    }

    fn parse_unit(&mut self) -> Unit {
        match self.parse_identifier().into_ascii_lower().as_slice() {
            "px" => Px,
            _ => panic!("unrecognized unit")
        }
    }

    fn parse_color(&mut self) -> Value {
        assert!(self.consume_char() == '#');
        ColorValue(Color {
            r: self.parse_hex_pair(),
            g: self.parse_hex_pair(),
            b: self.parse_hex_pair(),
            a: 255 })
    }

    /// Parse two hexadecimal digits.
    fn parse_hex_pair(&mut self) -> u8 {
        let s = self.input.as_slice().slice(self.pos, self.pos + 2);
        self.pos = self.pos + 2;
        FromStrRadix::from_str_radix(s, 0x10).unwrap()
    }

    /// Parse a property name or keyword.
    fn parse_identifier(&mut self) -> String {
        self.consume_while(valid_identifier_char)
    }

    /// Consume and discard zero or more whitespace characters.
    fn consume_whitespace(&mut self) {
        self.consume_while(|c| c.is_whitespace());
    }

    /// Consume characters until `test` returns false.
    fn consume_while(&mut self, test: |char| -> bool) -> String {
        let mut result = String::new();
        while !self.eof() && test(self.next_char()) {
            result.push(self.consume_char());
        }
        return result;
    }

    /// Return the current character, and advance self.pos to the next character.
    fn consume_char(&mut self) -> char {
        let range = self.input.as_slice().char_range_at(self.pos);
        self.pos = range.next;
        return range.ch;
    }

    /// Read the current character without consuming it.
    fn next_char(&self) -> char {
        self.input.as_slice().char_at(self.pos)
    }

    /// Return true if all input is consumed.
    fn eof(&self) -> bool {
        self.pos >= self.input.len()
    }
}

fn valid_identifier_char(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' | '0'...'9' | '-' | '_' => true, // TODO: Include U+00A0 and higher.
        _ => false,
    }
}
<|endoftext|>