<commit_before>use std::cmp;
use std::fmt;
use std::io::{self, Read, Write};
use std::ptr;

use futures::Async;
use tokio::io::Io;

use http::{Http1Transaction, h1, MessageHead, ParseResult};
use http::buf::{MemBuf, MemSlice};

const INIT_BUFFER_SIZE: usize = 4096;
pub const MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100;

pub struct Buffered<T> {
    io: T,
    read_buf: MemBuf,
    write_buf: WriteBuf,
}

impl<T> fmt::Debug for Buffered<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Buffered")
            .field("read_buf", &self.read_buf)
            .field("write_buf", &self.write_buf)
            .finish()
    }
}

impl<T: Io> Buffered<T> {
    pub fn new(io: T) -> Buffered<T> {
        Buffered {
            io: io,
            read_buf: MemBuf::new(),
            write_buf: WriteBuf::new(),
        }
    }

    pub fn read_buf(&self) -> &[u8] {
        self.read_buf.bytes()
    }

    pub fn consume_leading_lines(&mut self) {
        if !self.read_buf.is_empty() {
            let mut i = 0;
            while i < self.read_buf.len() {
                match self.read_buf.bytes()[i] {
                    b'\r' | b'\n' => i += 1,
                    _ => break,
                }
            }
            self.read_buf.slice(i);
        }
    }

    pub fn poll_read(&mut self) -> Async<()> {
        self.io.poll_read()
    }

    pub fn parse<S: Http1Transaction>(&mut self) -> ::Result<Option<MessageHead<S::Incoming>>> {
        self.reserve_read_buf();
        match self.read_buf.read_from(&mut self.io) {
            Ok(0) => {
                trace!("parse eof");
                return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "parse eof").into());
            }
            Ok(_) => {},
            Err(e) => match e.kind() {
                io::ErrorKind::WouldBlock => {},
                _ => return Err(e.into())
            }
        }
        match try!(parse::<S, _>(&self.read_buf)) {
            Some(head) => {
                //trace!("parsed {} bytes out of {}", len, self.read_buf.len());
                //self.read_buf.slice(len);
                Ok(Some(head.0))
            },
            None => {
                if self.read_buf.capacity() >= MAX_BUFFER_SIZE {
                    debug!("MAX_BUFFER_SIZE reached, closing");
                    Err(::Error::TooLarge)
                } else {
                    Ok(None)
                }
            },
        }
    }

    fn reserve_read_buf(&mut self) {
        self.read_buf.reserve(INIT_BUFFER_SIZE);
    }

    pub fn buffer<B: AsRef<[u8]>>(&mut self, buf: B) {
        self.write_buf.buffer(buf.as_ref());
    }

    #[cfg(test)]
    pub fn io_mut(&mut self) -> &mut T {
        &mut self.io
    }
}

/*
impl<T: Read> Read for Buffered<T> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        trace!("Buffered.read self={}, buf={}", self.read_buf.len(), buf.len());
        unimplemented!()
        /*
        let n = try!(self.read_buf.bytes().read(buf));
        self.read_buf.consume(n);
        if n == 0 {
            self.read_buf.reset();
            self.io.read(&mut buf[n..])
        } else {
            Ok(n)
        }
        */
    }
}
*/

impl<T: Write> Write for Buffered<T> {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        Ok(self.write_buf.buffer(data))
    }

    fn flush(&mut self) -> io::Result<()> {
        if self.write_buf.remaining() == 0 {
            Ok(())
        } else {
            loop {
                let n = try!(self.write_buf.write_into(&mut self.io));
                debug!("flushed {} bytes", n);
                if self.write_buf.remaining() == 0 {
                    return Ok(())
                }
            }
        }
    }
}

fn parse<T: Http1Transaction<Incoming=I>, I>(rdr: &MemBuf) -> ParseResult<I> {
    h1::parse::<T, I>(rdr)
}

pub trait MemRead {
    fn read_mem(&mut self, len: usize) -> io::Result<MemSlice>;
}

impl<T: Read> MemRead for Buffered<T> {
    fn read_mem(&mut self, len: usize) -> io::Result<MemSlice> {
        trace!("Buffered.read_mem read_buf={}, wanted={}", self.read_buf.len(), len);
        if !self.read_buf.is_empty() {
            let n = ::std::cmp::min(len, self.read_buf.len());
            trace!("Buffered.read_mem read_buf is not empty, slicing {}", n);
            Ok(self.read_buf.slice(n))
        } else {
            self.read_buf.reset();
            let n = try!(self.read_buf.read_from(&mut self.io));
            Ok(self.read_buf.slice(::std::cmp::min(len, n)))
        }
    }
}

#[derive(Clone)]
pub struct Cursor<T: AsRef<[u8]>> {
    bytes: T,
    pos: usize,
}

impl<T: AsRef<[u8]>> Cursor<T> {
    pub fn new(bytes: T) -> Cursor<T> {
        Cursor {
            bytes: bytes,
            pos: 0,
        }
    }

    pub fn is_written(&self) -> bool {
        trace!("Cursor::is_written pos = {}, len = {}", self.pos, self.bytes.as_ref().len());
        self.pos >= self.bytes.as_ref().len()
    }

    pub fn write_to<W: Write>(&mut self, dst: &mut W) -> io::Result<usize> {
        if self.remaining() == 0 {
            Ok(0)
        } else {
            dst.write(&self.bytes.as_ref()[self.pos..]).map(|n| {
                self.pos += n;
                n
            })
        }
    }

    fn remaining(&self) -> usize {
        self.bytes.as_ref().len() - self.pos
    }

    #[inline]
    pub fn buf(&self) -> &[u8] {
        &self.bytes.as_ref()[self.pos..]
    }

    #[inline]
    pub fn consume(&mut self, num: usize) {
        trace!("Cursor::consume({})", num);
        self.pos = ::std::cmp::min(self.bytes.as_ref().len(), self.pos + num);
    }
}

impl<T: AsRef<[u8]>> fmt::Debug for Cursor<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let bytes = self.buf();
        if bytes.len() > 32 {
            try!(f.write_str("Cursor(["));
            for byte in &bytes[..32] {
                try!(write!(f, "{:?}, ", byte));
            }
            write!(f, "... {}])", bytes.len())
        } else {
            write!(f, "Cursor({:?})", &bytes)
        }
    }
}

pub trait AtomicWrite {
    fn write_atomic(&mut self, data: &[&[u8]]) -> io::Result<usize>;
}

/*
#[cfg(not(windows))]
impl<T: Write + ::vecio::Writev> AtomicWrite for T {

    fn write_atomic(&mut self, bufs: &[&[u8]]) -> io::Result<usize> {
        self.writev(bufs)
    }

}

#[cfg(windows)]
*/
impl<T: Write> AtomicWrite for T {
    fn write_atomic(&mut self, bufs: &[&[u8]]) -> io::Result<usize> {
        let vec = bufs.concat();
        self.write(&vec)
    }
}
//}

// an internal buffer to collect writes before flushes
#[derive(Debug)]
struct WriteBuf(Cursor<Vec<u8>>);

impl WriteBuf {
    fn new() -> WriteBuf {
        WriteBuf(Cursor::new(Vec::new()))
    }

    fn write_into<W: Write>(&mut self, w: &mut W) -> io::Result<usize> {
        self.0.write_to(w)
    }

    fn buffer(&mut self, data: &[u8]) -> usize {
        trace!("WriteBuf::buffer() len = {:?}", data.len());
        self.maybe_reset();
        self.maybe_reserve(data.len());
        let mut vec = &mut self.0.bytes;
        let len = cmp::min(vec.capacity() - vec.len(), data.len());
        assert!(vec.capacity() - vec.len() >= len);
        unsafe {
            // in rust 1.9, we could use slice::copy_from_slice
            ptr::copy(
                data.as_ptr(),
                vec.as_mut_ptr().offset(vec.len() as isize),
                len
            );
            let new_len = vec.len() + len;
            vec.set_len(new_len);
        }
        len
    }

    fn remaining(&self) -> usize {
        self.0.remaining()
    }

    #[inline]
    fn maybe_reserve(&mut self, needed: usize) {
        let mut vec = &mut self.0.bytes;
        let cap = vec.capacity();
        if cap == 0 {
            let init = cmp::max(INIT_BUFFER_SIZE, needed);
            trace!("WriteBuf reserving initial {}", init);
            vec.reserve(init);
        } else if cap < MAX_BUFFER_SIZE {
            vec.reserve(cmp::min(needed, MAX_BUFFER_SIZE - cap));
            trace!("WriteBuf reserved {}", vec.capacity() - cap);
        }
    }

    fn maybe_reset(&mut self) {
        if self.0.pos != 0 && self.0.remaining() == 0 {
            self.0.pos = 0;
            unsafe {
                self.0.bytes.set_len(0);
            }
        }
    }
}

#[test]
fn test_iobuf_write_empty_slice() {
    use mock::{AsyncIo, Buf as MockBuf};

    let mut mock = AsyncIo::new(MockBuf::new(), 256);
    mock.error(io::Error::new(io::ErrorKind::Other, "logic error"));

    let mut io_buf = Buffered::new(mock);

    // underlying io will return the logic error upon write,
    // so we are testing that the io_buf does not trigger a write
    // when there is nothing to flush
    io_buf.flush().expect("should short-circuit flush");
}
<commit_msg>perf(http): reduce a copy when not using Chunked encoding<commit_after>use std::cmp;
use std::fmt;
use std::io::{self, Read, Write};
use std::ptr;

use futures::Async;
use tokio::io::Io;

use http::{Http1Transaction, h1, MessageHead, ParseResult};
use http::buf::{MemBuf, MemSlice};

const INIT_BUFFER_SIZE: usize = 4096;
pub const MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100;

pub struct Buffered<T> {
    io: T,
    read_buf: MemBuf,
    write_buf: WriteBuf,
}

impl<T> fmt::Debug for Buffered<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Buffered")
            .field("read_buf", &self.read_buf)
            .field("write_buf", &self.write_buf)
            .finish()
    }
}

impl<T: Io> Buffered<T> {
    pub fn new(io: T) -> Buffered<T> {
        Buffered {
            io: io,
            read_buf: MemBuf::new(),
            write_buf: WriteBuf::new(),
        }
    }

    pub fn read_buf(&self) -> &[u8] {
        self.read_buf.bytes()
    }

    pub fn consume_leading_lines(&mut self) {
        if !self.read_buf.is_empty() {
            let mut i = 0;
            while i < self.read_buf.len() {
                match self.read_buf.bytes()[i] {
                    b'\r' | b'\n' => i += 1,
                    _ => break,
                }
            }
            self.read_buf.slice(i);
        }
    }

    pub fn poll_read(&mut self) -> Async<()> {
        self.io.poll_read()
    }

    pub fn parse<S: Http1Transaction>(&mut self) -> ::Result<Option<MessageHead<S::Incoming>>> {
        self.reserve_read_buf();
        match self.read_buf.read_from(&mut self.io) {
            Ok(0) => {
                trace!("parse eof");
                return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "parse eof").into());
            }
            Ok(_) => {},
            Err(e) => match e.kind() {
                io::ErrorKind::WouldBlock => {},
                _ => return Err(e.into())
            }
        }
        match try!(parse::<S, _>(&self.read_buf)) {
            Some(head) => {
                //trace!("parsed {} bytes out of {}", len, self.read_buf.len());
                //self.read_buf.slice(len);
                Ok(Some(head.0))
            },
            None => {
                if self.read_buf.capacity() >= MAX_BUFFER_SIZE {
                    debug!("MAX_BUFFER_SIZE reached, closing");
                    Err(::Error::TooLarge)
                } else {
                    Ok(None)
                }
            },
        }
    }

    fn reserve_read_buf(&mut self) {
        self.read_buf.reserve(INIT_BUFFER_SIZE);
    }

    pub fn buffer<B: AsRef<[u8]>>(&mut self, buf: B) {
        self.write_buf.buffer(buf.as_ref());
    }

    #[cfg(test)]
    pub fn io_mut(&mut self) -> &mut T {
        &mut self.io
    }
}

/*
impl<T: Read> Read for Buffered<T> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        trace!("Buffered.read self={}, buf={}", self.read_buf.len(), buf.len());
        unimplemented!()
        /*
        let n = try!(self.read_buf.bytes().read(buf));
        self.read_buf.consume(n);
        if n == 0 {
            self.read_buf.reset();
            self.io.read(&mut buf[n..])
        } else {
            Ok(n)
        }
        */
    }
}
*/

impl<T: Write> Write for Buffered<T> {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        Ok(self.write_buf.buffer(data))
    }

    fn flush(&mut self) -> io::Result<()> {
        if self.write_buf.remaining() == 0 {
            Ok(())
        } else {
            loop {
                let n = try!(self.write_buf.write_into(&mut self.io));
                debug!("flushed {} bytes", n);
                if self.write_buf.remaining() == 0 {
                    return Ok(())
                }
            }
        }
    }
}

fn parse<T: Http1Transaction<Incoming=I>, I>(rdr: &MemBuf) -> ParseResult<I> {
    h1::parse::<T, I>(rdr)
}

pub trait MemRead {
    fn read_mem(&mut self, len: usize) -> io::Result<MemSlice>;
}

impl<T: Read> MemRead for Buffered<T> {
    fn read_mem(&mut self, len: usize) -> io::Result<MemSlice> {
        trace!("Buffered.read_mem read_buf={}, wanted={}", self.read_buf.len(), len);
        if !self.read_buf.is_empty() {
            let n = ::std::cmp::min(len, self.read_buf.len());
            trace!("Buffered.read_mem read_buf is not empty, slicing {}", n);
            Ok(self.read_buf.slice(n))
        } else {
            self.read_buf.reset();
            let n = try!(self.read_buf.read_from(&mut self.io));
            Ok(self.read_buf.slice(::std::cmp::min(len, n)))
        }
    }
}

#[derive(Clone)]
pub struct Cursor<T: AsRef<[u8]>> {
    bytes: T,
    pos: usize,
}

impl<T: AsRef<[u8]>> Cursor<T> {
    pub fn new(bytes: T) -> Cursor<T> {
        Cursor {
            bytes: bytes,
            pos: 0,
        }
    }

    pub fn is_written(&self) -> bool {
        trace!("Cursor::is_written pos = {}, len = {}", self.pos, self.bytes.as_ref().len());
        self.pos >= self.bytes.as_ref().len()
    }

    pub fn write_to<W: Write>(&mut self, dst: &mut W) -> io::Result<usize> {
        if self.remaining() == 0 {
            Ok(0)
        } else {
            dst.write(&self.bytes.as_ref()[self.pos..]).map(|n| {
                self.pos += n;
                n
            })
        }
    }

    fn remaining(&self) -> usize {
        self.bytes.as_ref().len() - self.pos
    }

    #[inline]
    pub fn buf(&self) -> &[u8] {
        &self.bytes.as_ref()[self.pos..]
    }

    #[inline]
    pub fn consume(&mut self, num: usize) {
        trace!("Cursor::consume({})", num);
        self.pos = ::std::cmp::min(self.bytes.as_ref().len(), self.pos + num);
    }
}

impl<T: AsRef<[u8]>> fmt::Debug for Cursor<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let bytes = self.buf();
        if bytes.len() > 32 {
            try!(f.write_str("Cursor(["));
            for byte in &bytes[..32] {
                try!(write!(f, "{:?}, ", byte));
            }
            write!(f, "... {}])", bytes.len())
        } else {
            write!(f, "Cursor({:?})", &bytes)
        }
    }
}

pub trait AtomicWrite {
    fn write_atomic(&mut self, data: &[&[u8]]) -> io::Result<usize>;
}

/*
#[cfg(not(windows))]
impl<T: Write + ::vecio::Writev> AtomicWrite for T {

    fn write_atomic(&mut self, bufs: &[&[u8]]) -> io::Result<usize> {
        self.writev(bufs)
    }

}

#[cfg(windows)]
*/
impl<T: Write> AtomicWrite for T {
    fn write_atomic(&mut self, bufs: &[&[u8]]) -> io::Result<usize> {
        if bufs.len() == 1 {
            self.write(bufs[0])
        } else {
            let vec = bufs.concat();
            self.write(&vec)
        }
    }
}
//}

// an internal buffer to collect writes before flushes
#[derive(Debug)]
struct WriteBuf(Cursor<Vec<u8>>);

impl WriteBuf {
    fn new() -> WriteBuf {
        WriteBuf(Cursor::new(Vec::new()))
    }

    fn write_into<W: Write>(&mut self, w: &mut W) -> io::Result<usize> {
        self.0.write_to(w)
    }

    fn buffer(&mut self, data: &[u8]) -> usize {
        trace!("WriteBuf::buffer() len = {:?}", data.len());
        self.maybe_reset();
        self.maybe_reserve(data.len());
        let mut vec = &mut self.0.bytes;
        let len = cmp::min(vec.capacity() - vec.len(), data.len());
        assert!(vec.capacity() - vec.len() >= len);
        unsafe {
            // in rust 1.9, we could use slice::copy_from_slice
            ptr::copy(
                data.as_ptr(),
                vec.as_mut_ptr().offset(vec.len() as isize),
                len
            );
            let new_len = vec.len() + len;
            vec.set_len(new_len);
        }
        len
    }

    fn remaining(&self) -> usize {
        self.0.remaining()
    }

    #[inline]
    fn maybe_reserve(&mut self, needed: usize) {
        let mut vec = &mut self.0.bytes;
        let cap = vec.capacity();
        if cap == 0 {
            let init = cmp::max(INIT_BUFFER_SIZE, needed);
            trace!("WriteBuf reserving initial {}", init);
            vec.reserve(init);
        } else if cap < MAX_BUFFER_SIZE {
            vec.reserve(cmp::min(needed, MAX_BUFFER_SIZE - cap));
            trace!("WriteBuf reserved {}", vec.capacity() - cap);
        }
    }

    fn maybe_reset(&mut self) {
        if self.0.pos != 0 && self.0.remaining() == 0 {
            self.0.pos = 0;
            unsafe {
                self.0.bytes.set_len(0);
            }
        }
    }
}

#[test]
fn test_iobuf_write_empty_slice() {
    use mock::{AsyncIo, Buf as MockBuf};

    let mut mock = AsyncIo::new(MockBuf::new(), 256);
    mock.error(io::Error::new(io::ErrorKind::Other, "logic error"));

    let mut io_buf = Buffered::new(mock);

    // underlying io will return the logic error upon write,
    // so we are testing that the io_buf does not trigger a write
    // when there is nothing to flush
    io_buf.flush().expect("should short-circuit flush");
}
<|endoftext|>


<commit_before>use std::fmt::{Display, Error, Formatter};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BinOp {
    Ge,
    Gt,
    Eql,       // ==
    EqlStrict, // ===
    Neq,       // !=
    NeqStrict, // !==
    Le,
    Lt,

    And,
    Or,

    BitOr,
    BitXor,
    BitAnd,

    ShiftLeft,
    ShiftRight,
    ShiftRightUnsigned,

    Minus,
    Plus,
    Slash,
    Star,
    Exponent,
    Mod,

    InstanceOf,
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 110,
    Sign = 100,
    Inc = 90,
    Mult = 70,
    Add = 60,
    Shift = 52,
    Cmp = 51,
    Equality = 50,
    BitAnd = 43,
    BitXor = 42,
    BitOr = 41,
    And = 40,
    Or = 30,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Ge | BinOp::Gt | BinOp::Le | BinOp::Lt | BinOp::InstanceOf => Precedence::Cmp,
            BinOp::Eql | BinOp::Neq | BinOp::EqlStrict | BinOp::NeqStrict => Precedence::Equality,
            BinOp::Or => Precedence::Or,
            BinOp::BitOr => Precedence::BitOr,
            BinOp::BitXor => Precedence::BitXor,
            BinOp::BitAnd => Precedence::BitAnd,
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star | BinOp::Exponent | BinOp::Mod => Precedence::Mult,
            BinOp::ShiftLeft | BinOp::ShiftRight | BinOp::ShiftRightUnsigned => Precedence::Shift,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Ge => write!(fmt, ">="),
            BinOp::Gt => write!(fmt, ">"),
            BinOp::Eql => write!(fmt, "=="),
            BinOp::EqlStrict => write!(fmt, "==="),
            BinOp::Le => write!(fmt, "<="),
            BinOp::Lt => write!(fmt, "<"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Neq => write!(fmt, "!="),
            BinOp::NeqStrict => write!(fmt, "!=="),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
            BinOp::Exponent => write!(fmt, "**"),
            BinOp::Mod => write!(fmt, "%"),
            BinOp::BitXor => write!(fmt, "^"),
            BinOp::BitOr => write!(fmt, "|"),
            BinOp::BitAnd => write!(fmt, "&"),
            BinOp::ShiftLeft => write!(fmt, "<<"),
            BinOp::ShiftRight => write!(fmt, ">>"),
            BinOp::ShiftRightUnsigned => write!(fmt, ">>>"),
            BinOp::InstanceOf => write!(fmt, "instanceof"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Exp {
    Array(Vec<Box<Exp>>),
    BitNot(Box<Exp>),
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Bool(bool),
    Call(Box<Exp>, Vec<Box<Exp>>),
    Defun(Option<String>, Vec<String>, Vec<Stmt>),
    Float(f64),
    InstanceVar(Box<Exp>, String),
    KeyAccessor(Box<Exp>, Box<Exp>),
    LogNot(Box<Exp>),
    Neg(Box<Exp>),
    Null,
    NewObject(Box<Exp>, Vec<Box<Exp>>),
    Object(Vec<(String, Box<Exp>)>),
    Pos(Box<Exp>),
    PostDec(Box<Exp>),
    PostInc(Box<Exp>),
    PreDec(Box<Exp>),
    PreInc(Box<Exp>),
    TypeOf(Box<Exp>),
    Str(String),
    Undefined,
    Var(String),
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::BitNot(_) | Exp::LogNot(_) | Exp::Neg(_) | Exp::Pos(_) => Precedence::Sign,
            Exp::PostDec(_) | Exp::PostInc(_) | Exp::PreDec(_) | Exp::PreInc(_) => Precedence::Inc,
            _ => Precedence::Const
        }
    }
}

macro_rules! group {
    ($e:expr, $p:expr) => {
        if $e.precedence() < $p {
            format!("({})", $e)
        } else {
            format!("{}", $e)
        }
    }
}

impl Exp {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! stmt_block {
            ($stmt:expr) => {
                for s in $stmt {
                    try!(s.fmt_helper(&mut fmt, indent_level + 2))
                }
            }
        }

        match *self {
            Exp::Array(ref vec) => {
                try!(write!(fmt, "["));

                for (i, elem) in vec.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", elem));
                }

                write!(fmt, "]")
            }
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::BitNot(ref e) => write!(fmt, "~{}", group!(e, Precedence::Sign)),
            Exp::Bool(b) => write!(fmt, "{}", b),
            Exp::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Exp::Defun(ref opt, ref params, ref body) => {
                try!(write!(fmt, "function"));

                if let &Some(ref func) = opt {
                    try!(write!(fmt, " {}", func));
                }

                try!(write!(fmt, "("));

                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(write!(fmt, ") {{\n"));
                stmt_block!(body);

                let indent : String = (0..indent_level).map(|_| " ").collect();

                write!(fmt, "{}}}", indent)
            }
            Exp::Float(f) => write!(fmt, "{}", f),
            Exp::InstanceVar(ref obj, ref name) => write!(fmt, "{}.{}", obj, name),
            Exp::KeyAccessor(ref obj, ref key) => write!(fmt, "{}[{}]", obj, key),
            Exp::LogNot(ref e) => write!(fmt, "!{}", group!(e, Precedence::Sign)),
            Exp::Neg(ref e) => write!(fmt, "-{}", group!(e, Precedence::Sign)),
            Exp::NewObject(ref name, ref args) => {
                try!(write!(fmt, "new {}(", name));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg))
                }

                write!(fmt, ")")
            }
            Exp::Null => write!(fmt, "null"),
            Exp::Object(ref properties) => {
                if properties.is_empty() {
                    return write!(fmt, "{{}}");
                }

                try!(writeln!(fmt, "{{"));

                let indent : String = (0..indent_level + 2).map(|_| " ").collect();

                for (i, &(ref name, ref prop)) in properties.iter().enumerate() {
                    if i != 0 {
                        try!(writeln!(fmt, ","));
                    }

                    try!(write!(fmt, "{}{}: ", indent, name));
                    try!(prop.fmt_helper(&mut fmt, indent_level + 2));
                }

                write!(fmt, "\n}}")
            }
            Exp::Pos(ref e) => write!(fmt, "+{}", group!(e, Precedence::Sign)),
            Exp::PostDec(ref e) => write!(fmt, "{}--", group!(e, Precedence::Inc)),
            Exp::PostInc(ref e) => write!(fmt, "{}++", group!(e, Precedence::Inc)),
            Exp::PreDec(ref e) => write!(fmt, "--{}", group!(e, Precedence::Inc)),
            Exp::PreInc(ref e) => write!(fmt, "++{}", group!(e, Precedence::Inc)),
            Exp::TypeOf(ref e) => write!(fmt, "typeof {}", e),
            Exp::Str(ref s) => write!(fmt, "\"{}\"", s),
            Exp::Undefined => write!(fmt, "undefined"),
            Exp::Var(ref v) => write!(fmt, "{}", v),
        }
    }
}

impl Display for Exp {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}

#[derive(Clone, Debug)]
pub enum Stmt {
    Assign(Exp, Exp),
    BareExp(Exp),
    Break,
    Continue,
    Decl(String, Exp),
    Empty,
    If(Exp, Vec<Stmt>, Vec<Stmt>),
    Ret(Exp),
    Seq(Box<Stmt>, Box<Stmt>),
    // try block, catch variable, catch block, finally block
    Try(Vec<Stmt>, String, Vec<Stmt>, Vec<Stmt>),
    Throw(Box<Exp>),
    VarDecl(String),
    While(Exp, Vec<Stmt>),
}

impl Stmt {
    pub fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! stmt_block {
            ($stmt:expr) => {
                for s in $stmt {
                    try!(s.fmt_helper(&mut fmt, indent_level + 2))
                }
            }
        }

        macro_rules! indented_stmt {
            ($s:expr) => {
                try!($s.fmt_helper(&mut fmt, indent_level + 2))
            }
        }

        macro_rules! exp_semi {
            ($exp:expr) => {{
                try!($exp.fmt_helper(&mut fmt, indent_level));
                writeln!(fmt, ";")
            }}
        }

        let indent : String = (0..indent_level).map(|_| " ").collect();

        match *self {
            Stmt::Assign(ref v, ref exp) => {
                try!(write!(fmt, "{}{} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::BareExp(ref exp) => {
                try!(write!(fmt, "{}", indent));
                exp_semi!(exp)
            }
            Stmt::Break => {
                write!(fmt, "break;")
            }
            Stmt::Continue => {
                write!(fmt, "continue;")
            }
            Stmt::Decl(ref v, ref exp) => {
                try!(write!(fmt, "{}var {} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::Empty => Ok(()),
            Stmt::If(ref e, ref s, ref els) => {
                try!(write!(fmt, "{}if (", indent));
                try!(e.fmt_helper(&mut fmt, indent_level + 2));
                try!(writeln!(fmt, ") {{\n"));
                stmt_block!(s);

                if els.len() > 0 {
                    stmt_block!(s);
                }

                //if let &Some(ref stmt) = els {
                //    try!(write!(fmt, "{}else {{\n", indent));
                //    indented_stmt!(stmt);
                //    try!(write!(fmt, "{}}}\n", indent));
                //}

                Ok(())
            }
            Stmt::Ret(ref e) => {
                try!(write!(fmt, "{}return ", indent));
                exp_semi!(e)
            }
            Stmt::Seq(ref s1, ref s2) => {
                try!(s1.fmt_helper(&mut fmt, indent_level));
                s2.fmt_helper(&mut fmt, indent_level)
            }
            Stmt::Throw(ref e) => {
                write!(fmt, "{}throw {}", indent, e)
            }
            Stmt::Try(ref stmt, ref catch_var, ref catch_block, ref finally_block) => {
                try!(write!(fmt, "{}try {{\n", indent));
                stmt_block!(stmt);
                try!(write!(fmt, "{}}}\n", indent));

                if catch_block.len() > 0 {
                    try!(write!(fmt, "{}catch ({}) {{\n", catch_var, indent));
                    stmt_block!(catch_block);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                if finally_block.len() > 0 {
                    try!(write!(fmt, "{}finally {{\n", indent));
                    stmt_block!(finally_block);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                Ok(())
            }
            Stmt::VarDecl(ref s) => {
                write!(fmt, "var {};", s)
            }
            Stmt::While(ref exp, ref stmt) => {
                try!(write!(fmt, "{}while ({}) {{\n", indent, exp));
                stmt_block!(stmt);
                write!(fmt, "{}}}\n", indent)
            }
        }
    }
}

impl Display for Stmt {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}
<commit_msg>for loops<commit_after>use std::fmt::{Display, Error, Formatter};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BinOp {
    Ge,
    Gt,
    Eql,       // ==
    EqlStrict, // ===
    Neq,       // !=
    NeqStrict, // !==
    Le,
    Lt,

    And,
    Or,

    BitOr,
    BitXor,
    BitAnd,

    ShiftLeft,
    ShiftRight,
    ShiftRightUnsigned,

    Minus,
    Plus,
    Slash,
    Star,
    Exponent,
    Mod,

    InstanceOf,
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 110,
    Sign = 100,
    Inc = 90,
    Mult = 70,
    Add = 60,
    Shift = 52,
    Cmp = 51,
    Equality = 50,
    BitAnd = 43,
    BitXor = 42,
    BitOr = 41,
    And = 40,
    Or = 30,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Ge | BinOp::Gt | BinOp::Le | BinOp::Lt | BinOp::InstanceOf => Precedence::Cmp,
            BinOp::Eql | BinOp::Neq | BinOp::EqlStrict | BinOp::NeqStrict => Precedence::Equality,
            BinOp::Or => Precedence::Or,
            BinOp::BitOr => Precedence::BitOr,
            BinOp::BitXor => Precedence::BitXor,
            BinOp::BitAnd => Precedence::BitAnd,
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star | BinOp::Exponent | BinOp::Mod => Precedence::Mult,
            BinOp::ShiftLeft | BinOp::ShiftRight | BinOp::ShiftRightUnsigned => Precedence::Shift,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Ge => write!(fmt, ">="),
            BinOp::Gt => write!(fmt, ">"),
            BinOp::Eql => write!(fmt, "=="),
            BinOp::EqlStrict => write!(fmt, "==="),
            BinOp::Le => write!(fmt, "<="),
            BinOp::Lt => write!(fmt, "<"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Neq => write!(fmt, "!="),
            BinOp::NeqStrict => write!(fmt, "!=="),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
            BinOp::Exponent => write!(fmt, "**"),
            BinOp::Mod => write!(fmt, "%"),
            BinOp::BitXor => write!(fmt, "^"),
            BinOp::BitOr => write!(fmt, "|"),
            BinOp::BitAnd => write!(fmt, "&"),
            BinOp::ShiftLeft => write!(fmt, "<<"),
            BinOp::ShiftRight => write!(fmt, ">>"),
            BinOp::ShiftRightUnsigned => write!(fmt, ">>>"),
            BinOp::InstanceOf => write!(fmt, "instanceof"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Exp {
    Array(Vec<Box<Exp>>),
    BitNot(Box<Exp>),
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Bool(bool),
    Call(Box<Exp>, Vec<Box<Exp>>),
    Defun(Option<String>, Vec<String>, Vec<Stmt>),
    Float(f64),
    InstanceVar(Box<Exp>, String),
    KeyAccessor(Box<Exp>, Box<Exp>),
    LogNot(Box<Exp>),
    Neg(Box<Exp>),
    Null,
    NewObject(Box<Exp>, Vec<Box<Exp>>),
    Object(Vec<(String, Box<Exp>)>),
    Pos(Box<Exp>),
    PostDec(Box<Exp>),
    PostInc(Box<Exp>),
    PreDec(Box<Exp>),
    PreInc(Box<Exp>),
    TypeOf(Box<Exp>),
    Str(String),
    Undefined,
    Var(String),
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::BitNot(_) | Exp::LogNot(_) | Exp::Neg(_) | Exp::Pos(_) => Precedence::Sign,
            Exp::PostDec(_) | Exp::PostInc(_) | Exp::PreDec(_) | Exp::PreInc(_) => Precedence::Inc,
            _ => Precedence::Const
        }
    }
}

macro_rules! group {
    ($e:expr, $p:expr) => {
        if $e.precedence() < $p {
            format!("({})", $e)
        } else {
            format!("{}", $e)
        }
    }
}

impl Exp {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! stmt_block {
            ($stmt:expr) => {
                for s in $stmt {
                    try!(s.fmt_helper(&mut fmt, indent_level + 2))
                }
            }
        }

        match *self {
            Exp::Array(ref vec) => {
                try!(write!(fmt, "["));

                for (i, elem) in vec.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", elem));
                }

                write!(fmt, "]")
            }
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::BitNot(ref e) => write!(fmt, "~{}", group!(e, Precedence::Sign)),
            Exp::Bool(b) => write!(fmt, "{}", b),
            Exp::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Exp::Defun(ref opt, ref params, ref body) => {
                try!(write!(fmt, "function"));

                if let &Some(ref func) = opt {
                    try!(write!(fmt, " {}", func));
                }

                try!(write!(fmt, "("));

                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(write!(fmt, ") {{\n"));
                stmt_block!(body);

                let indent : String = (0..indent_level).map(|_| " ").collect();

                write!(fmt, "{}}}", indent)
            }
            Exp::Float(f) => write!(fmt, "{}", f),
            Exp::InstanceVar(ref obj, ref name) => write!(fmt, "{}.{}", obj, name),
            Exp::KeyAccessor(ref obj, ref key) => write!(fmt, "{}[{}]", obj, key),
            Exp::LogNot(ref e) => write!(fmt, "!{}", group!(e, Precedence::Sign)),
            Exp::Neg(ref e) => write!(fmt, "-{}", group!(e, Precedence::Sign)),
            Exp::NewObject(ref name, ref args) => {
                try!(write!(fmt, "new {}(", name));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg))
                }

                write!(fmt, ")")
            }
            Exp::Null => write!(fmt, "null"),
            Exp::Object(ref properties) => {
                if properties.is_empty() {
                    return write!(fmt, "{{}}");
                }

                try!(writeln!(fmt, "{{"));

                let indent : String = (0..indent_level + 2).map(|_| " ").collect();

                for (i, &(ref name, ref prop)) in properties.iter().enumerate() {
                    if i != 0 {
                        try!(writeln!(fmt, ","));
                    }

                    try!(write!(fmt, "{}{}: ", indent, name));
                    try!(prop.fmt_helper(&mut fmt, indent_level + 2));
                }

                write!(fmt, "\n}}")
            }
            Exp::Pos(ref e) => write!(fmt, "+{}", group!(e, Precedence::Sign)),
            Exp::PostDec(ref e) => write!(fmt, "{}--", group!(e, Precedence::Inc)),
            Exp::PostInc(ref e) => write!(fmt, "{}++", group!(e, Precedence::Inc)),
            Exp::PreDec(ref e) => write!(fmt, "--{}", group!(e, Precedence::Inc)),
            Exp::PreInc(ref e) => write!(fmt, "++{}", group!(e, Precedence::Inc)),
            Exp::TypeOf(ref e) => write!(fmt, "typeof {}", e),
            Exp::Str(ref s) => write!(fmt, "\"{}\"", s),
            Exp::Undefined => write!(fmt, "undefined"),
            Exp::Var(ref v) => write!(fmt, "{}", v),
        }
    }
}

impl Display for Exp {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}

#[derive(Clone, Debug)]
pub enum Stmt {
    Assign(Exp, Exp),
    BareExp(Exp),
    Break,
    Continue,
    Decl(String, Exp),
    Empty,
    If(Exp, Vec<Stmt>, Vec<Stmt>),
    // for (initialization, condition, step) { block }
    For(Box<Stmt>, Exp, Exp, Vec<Stmt>),
    Ret(Exp),
    Seq(Box<Stmt>, Box<Stmt>),
    // try block, catch variable, catch block, finally block
    Try(Vec<Stmt>, String, Vec<Stmt>, Vec<Stmt>),
    Throw(Box<Exp>),
    VarDecl(String),
    While(Exp, Vec<Stmt>),
}

impl Stmt {
    pub fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! stmt_block {
            ($stmt:expr) => {
                for s in $stmt {
                    try!(s.fmt_helper(&mut fmt, indent_level + 2))
                }
            }
        }

        macro_rules! indented_stmt {
            ($s:expr) => {
                try!($s.fmt_helper(&mut fmt, indent_level + 2))
            }
        }

        macro_rules! exp_semi {
            ($exp:expr) => {{
                try!($exp.fmt_helper(&mut fmt, indent_level));
                writeln!(fmt, ";")
            }}
        }

        let indent : String = (0..indent_level).map(|_| " ").collect();

        match *self {
            Stmt::Assign(ref v, ref exp) => {
                try!(write!(fmt, "{}{} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::BareExp(ref exp) => {
                try!(write!(fmt, "{}", indent));
                exp_semi!(exp)
            }
            Stmt::Break => {
                write!(fmt, "break;")
            }
            Stmt::Continue => {
                write!(fmt, "continue;")
            }
            Stmt::Decl(ref v, ref exp) => {
                try!(write!(fmt, "{}var {} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::Empty => Ok(()),
            Stmt::If(ref e, ref s, ref els) => {
                try!(write!(fmt, "{}if (", indent));
                try!(e.fmt_helper(&mut fmt, indent_level + 2));
                try!(writeln!(fmt, ") {{\n"));
                stmt_block!(s);

                if els.len() > 0 {
                    stmt_block!(s);
                }

                //if let &Some(ref stmt) = els {
                //    try!(write!(fmt, "{}else {{\n", indent));
                //    indented_stmt!(stmt);
                //    try!(write!(fmt, "{}}}\n", indent));
                //}

                Ok(())
            }
            Stmt::For(ref init, ref cond, ref step, ref block) => {
                try!(write!(fmt, "{}for ({}; {}; {})", indent,
                                    init, cond, step));
                stmt_block!(block);
                Ok(())
            }
            Stmt::Ret(ref e) => {
                try!(write!(fmt, "{}return ", indent));
                exp_semi!(e)
            }
            Stmt::Seq(ref s1, ref s2) => {
                try!(s1.fmt_helper(&mut fmt, indent_level));
                s2.fmt_helper(&mut fmt, indent_level)
            }
            Stmt::Throw(ref e) => {
                write!(fmt, "{}throw {}", indent, e)
            }
            Stmt::Try(ref stmt, ref catch_var, ref catch_block, ref finally_block) => {
                try!(write!(fmt, "{}try {{\n", indent));
                stmt_block!(stmt);
                try!(write!(fmt, "{}}}\n", indent));

                if catch_block.len() > 0 {
                    try!(write!(fmt, "{}catch ({}) {{\n", catch_var, indent));
                    stmt_block!(catch_block);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                if finally_block.len() > 0 {
                    try!(write!(fmt, "{}finally {{\n", indent));
                    stmt_block!(finally_block);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                Ok(())
            }
            Stmt::VarDecl(ref s) => {
                write!(fmt, "var {};", s)
            }
            Stmt::While(ref exp, ref stmt) => {
                try!(write!(fmt, "{}while ({}) {{\n", indent, exp));
                stmt_block!(stmt);
                write!(fmt, "{}}}\n", indent)
            }
        }
    }
}

impl Display for Stmt {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}
<|endoftext|>


<commit_before>use ffi::*;
use element::Element;
use util::*;
use iterator::Iter;
use ::Transfer;
use reference::Reference;

use std::ops::{Deref, DerefMut};

/**
GstBin is an element that can contain other GstElement, allowing them to be managed as a group. Pads from the child elements can be ghosted to the bin, see GstGhostPad. This makes the bin look like any other elements and enables creation of higher-level abstraction elements.

A new GstBin is created with gst_bin_new(). Use a GstPipeline instead if you want to create a toplevel bin because a normal bin doesn't have a bus or handle clock distribution of its own.

After the bin has been created you will typically add elements to it with gst_bin_add(). You can remove elements with gst_bin_remove().

An element can be retrieved from a bin with gst_bin_get_by_name(), using the elements name. gst_bin_get_by_name_recurse_up() is mainly used for internal purposes and will query the parent bins when the element is not found in the current bin.

An iterator of elements in a bin can be retrieved with gst_bin_iterate_elements(). Various other iterators exist to retrieve the elements in a bin.

gst_object_unref() is used to drop your reference to the bin.

The “element-added” signal is fired whenever a new element is added to the bin. Likewise the “element-removed” signal is fired whenever an element is removed from the bin.
Notes

A GstBin internally intercepts every GstMessage posted by its children and implements the following default behaviour for each of them:

GST_MESSAGE_EOS

This message is only posted by sinks in the PLAYING state. If all sinks posted the EOS message, this bin will post and EOS message upwards.

GST_MESSAGE_SEGMENT_START

just collected and never forwarded upwards. The messages are used to decide when all elements have completed playback of their segment.

GST_MESSAGE_SEGMENT_DONE

Is posted by GstBin when all elements that posted a SEGMENT_START have posted a SEGMENT_DONE.

GST_MESSAGE_DURATION_CHANGED

Is posted by an element that detected a change in the stream duration. The default bin behaviour is to clear any cached duration values so that the next duration query will perform a full duration recalculation. The duration change is posted to the application so that it can refetch the new duration with a duration query. Note that these messages can be posted before the bin is prerolled, in which case the duration query might fail.

GST_MESSAGE_CLOCK_LOST

This message is posted by an element when it can no longer provide a clock. The default bin behaviour is to check if the lost clock was the one provided by the bin. If so and the bin is currently in the PLAYING state, the message is forwarded to the bin parent. This message is also generated when a clock provider is removed from the bin. If this message is received by the application, it should PAUSE the pipeline and set it back to PLAYING to force a new clock distribution.

GST_MESSAGE_CLOCK_PROVIDE

This message is generated when an element can provide a clock. This mostly happens when a new clock provider is added to the bin. The default behaviour of the bin is to mark the currently selected clock as dirty, which will perform a clock recalculation the next time the bin is asked to provide a clock. This message is never sent tot the application but is forwarded to the parent of the bin.

OTHERS

posted upwards.

A GstBin implements the following default behaviour for answering to a GstQuery:

GST_QUERY_DURATION

If the query has been asked before with the same format and the bin is a toplevel bin (ie. has no parent), use the cached previous value. If no previous value was cached, the query is sent to all sink elements in the bin and the MAXIMUM of all values is returned. If the bin is a toplevel bin the value is cached. If no sinks are available in the bin, the query fails.

GST_QUERY_POSITION

The query is sent to all sink elements in the bin and the MAXIMUM of all values is returned. If no sinks are available in the bin, the query fails.

OTHERS

the query is forwarded to all sink elements, the result of the first sink that answers the query successfully is returned. If no sink is in the bin, the query fails.

A GstBin will by default forward any event sent to it to all sink elements. If all the sinks return TRUE, the bin will also return TRUE, else FALSE is returned. If no sinks are in the bin, the event handler will return TRUE.*/
pub struct Bin{
    bin: Element
}

unsafe impl Sync for Bin {}
unsafe impl Send for Bin {}

impl Bin{
    /// Creates a new bin with the given name.
    pub fn new(name: &str) -> Option<Bin>{
        unsafe{
            let cname = CString::new(name).unwrap();
            let name = if name != "" {
                cname.as_ptr()
            } else {
                ptr::null()
            };
            let bin = gst_bin_new(name);
            if bin != ptr::null_mut(){
	            gst_object_ref_sink(mem::transmute(bin));
	            Bin::new_from_gst_bin(bin as *mut GstBin)
	        }else{
	            None
	        }
        }
    }

    /// Creates a new bin from an already existing raw pointer to a GstBin.
    /// The passed element has to be fully referenced
    pub unsafe fn new_from_gst_bin(element: *mut GstBin) -> Option<Bin>{
        match Element::new_from_gst_element(element as *mut GstElement){
            Some(element) => Some( Bin{ bin: element } ),
            None => None
        }
    }

    /// Adds the given element to the bin. Sets the element's parent,
    /// and thus adds a reference.
    ///
    /// If the element's pads are linked to other pads, the pads will
    /// be unlinked before the element is added to the bin.
    ///
    /// > When you add an element to an already-running pipeline, you
    /// > will have to take care to set the state of the newly-added
    /// > element to the desired state (usually PLAYING or PAUSED, same
    /// > you set the pipeline to originally) with Element::set_state(),
    /// > or use gst_element_sync_state_with_parent(). The bin or pipeline
    /// > will not take care of this for you.
    pub fn add<E: Into<Element>>(&mut self, element: E) -> bool{
        unsafe{
            gst_bin_add(self.gst_bin_mut(), element.into().transfer()) == 1
        }
    }

    pub fn add_and_link<E: Into<Element>>(&mut self, src: E, sink: E) -> bool{
        let mut src = src.into();
        let mut sink = sink.into();
        self.add(src.reference()) &&
        self.add(sink.reference()) &&
        src.link(&mut sink)
    }

    pub fn add_many(&mut self, elements: Vec<Element>)->bool{
        elements.into_iter().fold(true, |ret, e| {
            ret && self.add(e)
        })
    }

    pub fn add_and_link_many(&mut self, mut elements: Vec<Element>)->bool{
        elements.iter().fold(true, |ret, element|{
            ret && self.add(element.reference())
        }) && Element::link_many(&elements.iter_mut().collect::<Vec<_>>())
    }

    /// Remove the element from its associated bin.
    ///
    /// If the element's pads are linked to other pads, the pads will be
    /// unlinked before the element is removed from the bin.
    pub fn remove(&mut self, element: &Element) -> bool{
        unsafe{
            gst_bin_remove(self.gst_bin_mut(), mem::transmute(element.gst_element())) == 1
        }
    }

    /// Get the element with the given name from this bin.
    ///
    /// Returns None if no element with the given name is found in the bin.
    pub fn get_by_name(&self, name: &str) -> Option<Element>{
        let cname = CString::new(name).unwrap();
        unsafe{
            let element = gst_bin_get_by_name(self.gst_bin() as *mut GstBin, cname.as_ptr());
            Element::new_from_gst_element(element)
        }
    }

    /// Gets the element with the given name from this bin.
    /// If the element is not found, a recursion is performed on the parent bin.
    ///
    /// Returns None if no element with the given name is found in the bin.
    pub fn get_by_name_recurse_up(&self, name: &str) -> Option<Element>{
        let cname = CString::new(name).unwrap();
        unsafe{
            let element = gst_bin_get_by_name_recurse_up(self.gst_bin() as *mut GstBin, cname.as_ptr());
            Element::new_from_gst_element(element)
        }
    }

    // Gets an iterator for the elements in this bin.
    pub fn iter(&self) -> Iter<Element>{
        unsafe{
            let bin = self.bin.gst_element() as *mut GstBin;
            Iter::new_from_gst_iterator(gst_bin_iterate_elements(bin)).unwrap()
        }
    }

    /// Query bin for the current latency using and reconfigures this latency
    /// to all the elements with a LATENCY event.
	///
	/// This method is typically called on the pipeline when a
	/// GST_MESSAGE_LATENCY is posted on the bus.
	///
	/// This function simply emits the 'do-latency' signal so any custom
	/// latency calculations will be performed.
    pub fn recalculate_latency(&mut self) -> bool{
        unsafe{
            gst_bin_recalculate_latency(self.gst_bin() as *mut GstBin) == 1
        }
    }

    /// If set to true, the bin will handle asynchronous state changes.
    /// This should be used only if the bin subclass is modifying the state
    /// of its children on its own
    pub fn set_async_handling(&mut self, async: bool){
        self.set("async-handling", async);
    }

    /// Forward all children messages, even those that would normally be
    /// filtered by the bin. This can be interesting when one wants to be
    /// notified of the EOS state of individual elements, for example.
	///
	/// The messages are converted to an ELEMENT message with the bin as the
	/// source. The structure of the message is named 'GstBinForwarded' and
	/// contains a field named 'message' of type GST_TYPE_MESSAGE that
	/// contains the original forwarded message.
    pub fn set_message_forward(&mut self, forward: bool){
        self.set("message-forward", forward);
    }

    /// Returns a const raw pointer to the internal GstElement
    pub unsafe fn gst_bin(&self) -> *const GstBin{
        self.bin.gst_element() as *const GstBin
    }

    /// Returns a mut raw pointer to the internal GstElement
    pub unsafe fn gst_bin_mut(&mut self) -> *mut GstBin{
        self.bin.gst_element() as *mut GstBin
    }
}

impl AsRef<Element> for Bin{
    fn as_ref(&self) -> &Element{
        &self.bin
    }
}

impl AsMut<Element> for Bin{
    fn as_mut(&mut self) -> &mut Element{
        &mut self.bin
    }
}

impl From<Bin> for Element{
    fn from(b: Bin) -> Element{
        b.bin
    }
}

impl Deref for Bin{
    type Target = Element;
    fn deref(&self) -> &Element{
        &self.bin
    }
}

impl DerefMut for Bin{
    fn deref_mut(&mut self) -> &mut Element{
        &mut self.bin
    }
}

impl ::Transfer for Bin{
    unsafe fn transfer(self) -> *mut GstElement{
        self.bin.transfer()
    }
}

impl Reference for Bin{
    fn reference(&self) -> Bin{
        Bin{bin: self.bin.reference()}
    }
}
<commit_msg>Bin: add iter_recurse<commit_after>use ffi::*;
use element::Element;
use util::*;
use iterator::Iter;
use ::Transfer;
use reference::Reference;

use std::ops::{Deref, DerefMut};

/**
GstBin is an element that can contain other GstElement, allowing them to be managed as a group. Pads from the child elements can be ghosted to the bin, see GstGhostPad. This makes the bin look like any other elements and enables creation of higher-level abstraction elements.

A new GstBin is created with gst_bin_new(). Use a GstPipeline instead if you want to create a toplevel bin because a normal bin doesn't have a bus or handle clock distribution of its own.

After the bin has been created you will typically add elements to it with gst_bin_add(). You can remove elements with gst_bin_remove().

An element can be retrieved from a bin with gst_bin_get_by_name(), using the elements name. gst_bin_get_by_name_recurse_up() is mainly used for internal purposes and will query the parent bins when the element is not found in the current bin.

An iterator of elements in a bin can be retrieved with gst_bin_iterate_elements(). Various other iterators exist to retrieve the elements in a bin.

gst_object_unref() is used to drop your reference to the bin.

The “element-added” signal is fired whenever a new element is added to the bin. Likewise the “element-removed” signal is fired whenever an element is removed from the bin.
Notes

A GstBin internally intercepts every GstMessage posted by its children and implements the following default behaviour for each of them:

GST_MESSAGE_EOS

This message is only posted by sinks in the PLAYING state. If all sinks posted the EOS message, this bin will post and EOS message upwards.

GST_MESSAGE_SEGMENT_START

just collected and never forwarded upwards. The messages are used to decide when all elements have completed playback of their segment.

GST_MESSAGE_SEGMENT_DONE

Is posted by GstBin when all elements that posted a SEGMENT_START have posted a SEGMENT_DONE.

GST_MESSAGE_DURATION_CHANGED

Is posted by an element that detected a change in the stream duration. The default bin behaviour is to clear any cached duration values so that the next duration query will perform a full duration recalculation. The duration change is posted to the application so that it can refetch the new duration with a duration query. Note that these messages can be posted before the bin is prerolled, in which case the duration query might fail.

GST_MESSAGE_CLOCK_LOST

This message is posted by an element when it can no longer provide a clock. The default bin behaviour is to check if the lost clock was the one provided by the bin. If so and the bin is currently in the PLAYING state, the message is forwarded to the bin parent. This message is also generated when a clock provider is removed from the bin. If this message is received by the application, it should PAUSE the pipeline and set it back to PLAYING to force a new clock distribution.

GST_MESSAGE_CLOCK_PROVIDE

This message is generated when an element can provide a clock. This mostly happens when a new clock provider is added to the bin. The default behaviour of the bin is to mark the currently selected clock as dirty, which will perform a clock recalculation the next time the bin is asked to provide a clock. This message is never sent tot the application but is forwarded to the parent of the bin.

OTHERS

posted upwards.

A GstBin implements the following default behaviour for answering to a GstQuery:

GST_QUERY_DURATION

If the query has been asked before with the same format and the bin is a toplevel bin (ie. has no parent), use the cached previous value. If no previous value was cached, the query is sent to all sink elements in the bin and the MAXIMUM of all values is returned. If the bin is a toplevel bin the value is cached. If no sinks are available in the bin, the query fails.

GST_QUERY_POSITION

The query is sent to all sink elements in the bin and the MAXIMUM of all values is returned. If no sinks are available in the bin, the query fails.

OTHERS

the query is forwarded to all sink elements, the result of the first sink that answers the query successfully is returned. If no sink is in the bin, the query fails.

A GstBin will by default forward any event sent to it to all sink elements. If all the sinks return TRUE, the bin will also return TRUE, else FALSE is returned. If no sinks are in the bin, the event handler will return TRUE.*/
pub struct Bin{
    bin: Element
}

unsafe impl Sync for Bin {}
unsafe impl Send for Bin {}

impl Bin{
    /// Creates a new bin with the given name.
    pub fn new(name: &str) -> Option<Bin>{
        unsafe{
            let cname = CString::new(name).unwrap();
            let name = if name != "" {
                cname.as_ptr()
            } else {
                ptr::null()
            };
            let bin = gst_bin_new(name);
            if bin != ptr::null_mut(){
	            gst_object_ref_sink(mem::transmute(bin));
	            Bin::new_from_gst_bin(bin as *mut GstBin)
	        }else{
	            None
	        }
        }
    }

    /// Creates a new bin from an already existing raw pointer to a GstBin.
    /// The passed element has to be fully referenced
    pub unsafe fn new_from_gst_bin(element: *mut GstBin) -> Option<Bin>{
        match Element::new_from_gst_element(element as *mut GstElement){
            Some(element) => Some( Bin{ bin: element } ),
            None => None
        }
    }

    /// Adds the given element to the bin. Sets the element's parent,
    /// and thus adds a reference.
    ///
    /// If the element's pads are linked to other pads, the pads will
    /// be unlinked before the element is added to the bin.
    ///
    /// > When you add an element to an already-running pipeline, you
    /// > will have to take care to set the state of the newly-added
    /// > element to the desired state (usually PLAYING or PAUSED, same
    /// > you set the pipeline to originally) with Element::set_state(),
    /// > or use gst_element_sync_state_with_parent(). The bin or pipeline
    /// > will not take care of this for you.
    pub fn add<E: Into<Element>>(&mut self, element: E) -> bool{
        unsafe{
            gst_bin_add(self.gst_bin_mut(), element.into().transfer()) == 1
        }
    }

    pub fn add_and_link<E: Into<Element>>(&mut self, src: E, sink: E) -> bool{
        let mut src = src.into();
        let mut sink = sink.into();
        self.add(src.reference()) &&
        self.add(sink.reference()) &&
        src.link(&mut sink)
    }

    pub fn add_many(&mut self, elements: Vec<Element>)->bool{
        elements.into_iter().fold(true, |ret, e| {
            ret && self.add(e)
        })
    }

    pub fn add_and_link_many(&mut self, mut elements: Vec<Element>)->bool{
        elements.iter().fold(true, |ret, element|{
            ret && self.add(element.reference())
        }) && Element::link_many(&elements.iter_mut().collect::<Vec<_>>())
    }

    /// Remove the element from its associated bin.
    ///
    /// If the element's pads are linked to other pads, the pads will be
    /// unlinked before the element is removed from the bin.
    pub fn remove(&mut self, element: &Element) -> bool{
        unsafe{
            gst_bin_remove(self.gst_bin_mut(), mem::transmute(element.gst_element())) == 1
        }
    }

    /// Get the element with the given name from this bin.
    ///
    /// Returns None if no element with the given name is found in the bin.
    pub fn get_by_name(&self, name: &str) -> Option<Element>{
        let cname = CString::new(name).unwrap();
        unsafe{
            let element = gst_bin_get_by_name(self.gst_bin() as *mut GstBin, cname.as_ptr());
            Element::new_from_gst_element(element)
        }
    }

    /// Gets the element with the given name from this bin.
    /// If the element is not found, a recursion is performed on the parent bin.
    ///
    /// Returns None if no element with the given name is found in the bin.
    pub fn get_by_name_recurse_up(&self, name: &str) -> Option<Element>{
        let cname = CString::new(name).unwrap();
        unsafe{
            let element = gst_bin_get_by_name_recurse_up(self.gst_bin() as *mut GstBin, cname.as_ptr());
            Element::new_from_gst_element(element)
        }
    }

    // Gets an iterator for the elements in this bin.
    pub fn iter(&self) -> Iter<Element>{
        unsafe{
            let bin = self.bin.gst_element() as *mut GstBin;
            Iter::new_from_gst_iterator(gst_bin_iterate_elements(bin)).unwrap()
        }
    }

    // Gets an iterator for the elements in this bin.
    pub fn iter_recurse(&self) -> Iter<Element>{
        unsafe{
            let bin = self.bin.gst_element() as *mut GstBin;
            Iter::new_from_gst_iterator(gst_bin_iterate_recurse(bin)).unwrap()
        }
    }

    /// Query bin for the current latency using and reconfigures this latency
    /// to all the elements with a LATENCY event.
	///
	/// This method is typically called on the pipeline when a
	/// GST_MESSAGE_LATENCY is posted on the bus.
	///
	/// This function simply emits the 'do-latency' signal so any custom
	/// latency calculations will be performed.
    pub fn recalculate_latency(&mut self) -> bool{
        unsafe{
            gst_bin_recalculate_latency(self.gst_bin() as *mut GstBin) == 1
        }
    }

    /// If set to true, the bin will handle asynchronous state changes.
    /// This should be used only if the bin subclass is modifying the state
    /// of its children on its own
    pub fn set_async_handling(&mut self, async: bool){
        self.set("async-handling", async);
    }

    /// Forward all children messages, even those that would normally be
    /// filtered by the bin. This can be interesting when one wants to be
    /// notified of the EOS state of individual elements, for example.
	///
	/// The messages are converted to an ELEMENT message with the bin as the
	/// source. The structure of the message is named 'GstBinForwarded' and
	/// contains a field named 'message' of type GST_TYPE_MESSAGE that
	/// contains the original forwarded message.
    pub fn set_message_forward(&mut self, forward: bool){
        self.set("message-forward", forward);
    }

    /// Returns a const raw pointer to the internal GstElement
    pub unsafe fn gst_bin(&self) -> *const GstBin{
        self.bin.gst_element() as *const GstBin
    }

    /// Returns a mut raw pointer to the internal GstElement
    pub unsafe fn gst_bin_mut(&mut self) -> *mut GstBin{
        self.bin.gst_element() as *mut GstBin
    }
}

impl AsRef<Element> for Bin{
    fn as_ref(&self) -> &Element{
        &self.bin
    }
}

impl AsMut<Element> for Bin{
    fn as_mut(&mut self) -> &mut Element{
        &mut self.bin
    }
}

impl From<Bin> for Element{
    fn from(b: Bin) -> Element{
        b.bin
    }
}

impl Deref for Bin{
    type Target = Element;
    fn deref(&self) -> &Element{
        &self.bin
    }
}

impl DerefMut for Bin{
    fn deref_mut(&mut self) -> &mut Element{
        &mut self.bin
    }
}

impl ::Transfer for Bin{
    unsafe fn transfer(self) -> *mut GstElement{
        self.bin.transfer()
    }
}

impl Reference for Bin{
    fn reference(&self) -> Bin{
        Bin{bin: self.bin.reference()}
    }
}
<|endoftext|>


<commit_before>// TODO: use Impls https://github.com/iron/iron/blob/master/src/iron.rs

use collections::dlist::DList;
use collections::Deque;

static CHB_MIN_SIZE:uint = 32u;

// TODO: move to utils
fn blit<T:Clone>(src: &[T], src_ofs: uint, dst: &mut [T], dst_ofs: uint, len: uint) {
    if (src_ofs > src.len() - len) || (dst_ofs > dst.len() - len) {
        fail!("blit: invalid argument!");
    }
    let sd = dst.mut_slice(dst_ofs, dst_ofs + len);
    let ss = src.slice(src_ofs, src_ofs + len);
    let _ = sd.clone_from_slice(ss);
}

/// Chained buffer of bytes.
/// Consists of linked list of nodes.
pub struct ChbChain {
    head: DList<Box<ChbNode>>,
    length: uint
}

impl ChbChain {

    fn new() -> ChbChain {
        return ChbChain{
            head: DList::new(),
            length: 0
        }
    }

    // TODO: rename len()?
    fn size(&self) {
        self.length
    }

    // XXX: maybe DEDUP append/prepend?
    // TODO: test: length, capacity, node size
    pub fn append_bytes(mut self, data: &[u8]) {
        let size = data.len();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
        let should_create = match self.head.back() {
            Some(nd) => {
                // Check is READONLY
                nd.room() < size
            }
            None => {
                true
            }
        };
        if should_create {
            self.create_node_tail(size);
        }
        // node could not be None here
        let node = self.head.back_mut().unwrap();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6268
        let end = node.end;
        blit(data.as_slice(), 0,
             node.dh.data.as_mut_slice(), end,
             size);
        node.end += size;
        self.length += size;
    }

    // TODO: test: length, capacity, node size
    pub fn prepend_bytes(&mut self, data: &[u8]) {
        let size = data.len();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
        let should_create = match self.head.front() {
            Some(nd) => {
                // Check is READONLY
                size > nd.start
            }
            None => {
                true
            }
        };
        if should_create {
            self.create_node_head(size);
        }
        // node could not be None here
        let node = self.head.front_mut().unwrap();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6268
        let start = node.start;
        blit(data.as_slice(), 0,
             node.dh.data.as_mut_slice(), start - size,
             size);
        node.start -= size;
        self.length += size;
    }

    pub fn pullup(&mut self, size: uint) -> Option<&[u8]> {
        if size == 0 || size > chb_size(chb) {
            return None
        }
        // let node = match chb.head
    }

    // XXX: private

    // TODO: rename _back
    fn add_node_tail(&mut self, node: Box<ChbNode>) {
        self.length += node.size();
        self.head.push(node);
    }

    // TODO: rename _front
    fn add_node_head(&mut self, node: Box<ChbNode>) {
        self.length += node.size();
        self.head.push_front(node);
    }

    // TODO: rename _back
    // TODO: remove?
    fn create_node_tail(&mut self, size: uint) {
        let nsize = if size < CHB_MIN_SIZE {
            size << 1
        } else {
            size
        };
        let node = ChbNode::new(ChbDataHolder::new(nsize)); // Box<ChbNode>
        self.add_node_tail(node);
    }

    // TODO: rename _front
    fn create_node_head(&mut self, size: uint) {
        let nsize = if size < CHB_MIN_SIZE {
            size << 1
        } else {
            size
        };
        let mut node = ChbNode::new(ChbDataHolder::new(nsize)); // Box<ChbNode>
        let r = node.room()
        node.start = r;
        node.end = r;
        self.add_node_head(node);
    }
}

/// Node of chain buffer.
/// Owned by ChbChain.
struct ChbNode {
    dh: Box<ChbDataHolder>, // можно заменить на RC
    start: uint,
    end: uint
}

impl ChbNode {
    pub fn new(dh: Box<ChbDataHolder>) -> Box<ChbNode> {
        let n = box ChbNode {
            dh: dh,
            start: 0,
            end: 0
        };
        // TODO: ref dh ? auto, when using RC
        return n;
    }

    pub fn size(&self) -> uint {
        self.end - self.start
    }

    pub fn room(&self) -> uint {
        return self.dh.size - self.end;
    }
}

/// Data holder
/// TODO: can be shared among different chains
/// TODO: implement other storages: shmem, mmap
struct ChbDataHolder{
    size: uint,
    data: Vec<u8>
}

impl ChbDataHolder {
    pub new(size: uint) -> Box<ChbDataHolder> {
        let dh = box ChbDataHolder {
            size: size,
            data: Vec::from_elem(size, 0)
        };
        return dh;
    }
}

// TODO: move to test
// let mut chain = Chb::new();
// chain.append_bytes("abcdefghijklmnop".as_bytes());
// chain.prepend_bytes("xxx".as_bytes());
<commit_msg>[fix] couple of refactoring errors<commit_after>// TODO: use Impls https://github.com/iron/iron/blob/master/src/iron.rs

extern crate collections;

use collections::dlist::DList;
use collections::Deque;

static CHB_MIN_SIZE:uint = 32u;

// TODO: move to utils
fn blit<T:Clone>(src: &[T], src_ofs: uint, dst: &mut [T], dst_ofs: uint, len: uint) {
    if (src_ofs > src.len() - len) || (dst_ofs > dst.len() - len) {
        fail!("blit: invalid argument!");
    }
    let sd = dst.mut_slice(dst_ofs, dst_ofs + len);
    let ss = src.slice(src_ofs, src_ofs + len);
    let _ = sd.clone_from_slice(ss);
}

/// Chained buffer of bytes.
/// Consists of linked list of nodes.
pub struct ChbChain {
    head: DList<Box<ChbNode>>,
    length: uint
}

impl ChbChain {

    fn new() -> ChbChain {
        return ChbChain{
            head: DList::new(),
            length: 0
        }
    }

    // TODO: rename len()?
    fn size(&self) {
        self.length
    }

    // XXX: maybe DEDUP append/prepend?
    // TODO: test: length, capacity, node size
    pub fn append_bytes(mut self, data: &[u8]) {
        let size = data.len();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
        let should_create = match self.head.back() {
            Some(nd) => {
                // Check is READONLY
                nd.room() < size
            }
            None => {
                true
            }
        };
        if should_create {
            self.create_node_tail(size);
        }
        // node could not be None here
        let node = self.head.back_mut().unwrap();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6268
        let end = node.end;
        blit(data.as_slice(), 0,
             node.dh.data.as_mut_slice(), end,
             size);
        node.end += size;
        self.length += size;
    }

    // TODO: test: length, capacity, node size
    pub fn prepend_bytes(&mut self, data: &[u8]) {
        let size = data.len();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6393
        let should_create = match self.head.front() {
            Some(nd) => {
                // Check is READONLY
                size > nd.start
            }
            None => {
                true
            }
        };
        if should_create {
            self.create_node_head(size);
        }
        // node could not be None here
        let node = self.head.front_mut().unwrap();
        // XXX: Damn, https://github.com/rust-lang/rust/issues/6268
        let start = node.start;
        blit(data.as_slice(), 0,
             node.dh.data.as_mut_slice(), start - size,
             size);
        node.start -= size;
        self.length += size;
    }

    pub fn pullup(&mut self, size: uint) -> Option<&[u8]> {
        if size == 0 || size > self.size() {
            return None
        }
        // let node = match chb.head
        None
    }

    // XXX: private

    // TODO: rename _back
    fn add_node_tail(&mut self, node: Box<ChbNode>) {
        self.length += node.size();
        self.head.push(node);
    }

    // TODO: rename _front
    fn add_node_head(&mut self, node: Box<ChbNode>) {
        self.length += node.size();
        self.head.push_front(node);
    }

    // TODO: rename _back
    // TODO: remove?
    fn create_node_tail(&mut self, size: uint) {
        let nsize = if size < CHB_MIN_SIZE {
            size << 1
        } else {
            size
        };
        let node = ChbNode::new(ChbDataHolder::new(nsize)); // Box<ChbNode>
        self.add_node_tail(node);
    }

    // TODO: rename _front
    fn create_node_head(&mut self, size: uint) {
        let nsize = if size < CHB_MIN_SIZE {
            size << 1
        } else {
            size
        };
        let mut node = ChbNode::new(ChbDataHolder::new(nsize)); // Box<ChbNode>
        let r = node.room();
        node.start = r;
        node.end = r;
        self.add_node_head(node);
    }
}

/// Node of chain buffer.
/// Owned by ChbChain.
struct ChbNode {
    dh: Box<ChbDataHolder>, // можно заменить на RC
    start: uint,
    end: uint
}

impl ChbNode {
    pub fn new(dh: Box<ChbDataHolder>) -> Box<ChbNode> {
        let n = box ChbNode {
            dh: dh,
            start: 0,
            end: 0
        };
        // TODO: ref dh ? auto, when using RC
        return n;
    }

    pub fn size(&self) -> uint {
        self.end - self.start
    }

    pub fn room(&self) -> uint {
        return self.dh.size - self.end;
    }
}

/// Data holder
/// TODO: can be shared among different chains
/// TODO: implement other storages: shmem, mmap
struct ChbDataHolder{
    size: uint,
    data: Vec<u8>
}

impl ChbDataHolder {
    pub fn new(size: uint) -> Box<ChbDataHolder> {
        let dh = box ChbDataHolder {
            size: size,
            data: Vec::from_elem(size, 0)
        };
        return dh;
    }
}

// TODO: move to test
// let mut chain = Chb::new();
// chain.append_bytes("abcdefghijklmnop".as_bytes());
// chain.prepend_bytes("xxx".as_bytes());
<|endoftext|>


<commit_before>use time;
use std::io;
use std::io::prelude::*;
use std::collections::HashMap;

use editor::text_from_editor;
use storage::Storage;

const DB_PATH: &'static str = "~/.notes";
const TIME_FORMAT: &'static str = "%d-%m-%Y %H:%M:%S";

pub enum Action {
    Output(String),
    Exit,
    None,
}

pub struct Cli {
    current_book: Option<usize>,
    storage: Storage,
}

impl Cli {
    pub fn new() -> Cli {
        let mut cli = Cli {
            current_book: None,
            storage: Storage::new(DB_PATH).unwrap(),
        };

        cli.storage.load();

        cli
    }

    pub fn run(&mut self) {
        loop {
            print!("notes> ");
            io::stdout().flush().expect("Flush failed");

            let mut input = String::new();
            match io::stdin().read_line(&mut input) {
                Err(_) => continue,
                Ok(_) => {
                    // EoF reached
                    if input.is_empty() {
                        println!("");
                        break;
                    }

                    input = input.trim().to_string();
                    if input.is_empty() {
                        continue;
                    }

                    match self.process_command(&input) {
                        Action::Output(output) => println!("{}", output),
                        Action::Exit => break,
                        Action::None => (),
                    }
                },
            }
        }

        println!("Bye!");
    }

    fn process_command(&mut self, command: &str) -> Action {
        match command {
            "ls" => self.ls(),
            "add" => self.add(),
            "exit" => self.exit(),
            "quit" => self.exit(),
            _ => Action::Output("No such command!".to_string()),
        }
    }

    fn ls(&mut self) -> Action {
        let mut result = String::new();

        for book in self.storage.books() {
            result.push_str(&book.title);
        }

        Action::Output(result)
    }

    fn add(&mut self) -> Action {
        let date = match time::strftime(TIME_FORMAT, &time::now()) {
            Ok(date) => date,
            Err(_) => String::from("(unknown)"),
        };

        let content = text_from_editor();

        let entry = format!("\n{}\n\n{}", date, content);

        self.storage.add_entry(entry);

        Action::Output("Entry added".to_string())
    }

    fn exit(&mut self) -> Action {
        Action::Exit
    }
}
<commit_msg>Support custom prompt and command args<commit_after>use time;
use std::io;
use std::io::prelude::*;
use std::collections::HashMap;

use editor::text_from_editor;
use storage::Storage;

const DB_PATH: &'static str = "~/.notes";
const TIME_FORMAT: &'static str = "%d-%m-%Y %H:%M:%S";

pub enum Action {
    Output(String),
    Exit,
    None,
}

pub struct Cli {
    current_book: Option<usize>,
    storage: Storage,
}

impl Cli {
    pub fn new() -> Cli {
        let mut cli = Cli {
            current_book: None,
            storage: Storage::new(DB_PATH).unwrap(),
        };

        cli.storage.load();

        cli
    }

    pub fn run(&mut self) {
        loop {
            let prompt = match self.current_book {
                Some(book) => self.storage.books()[book].title.clone(),
                None => String::new(),
            };

            print!("{}> ", prompt);
            io::stdout().flush().expect("Flush failed");

            let mut input = String::new();
            match io::stdin().read_line(&mut input) {
                Err(_) => continue,
                Ok(_) => {
                    // EoF reached
                    if input.is_empty() {
                        println!("");
                        break;
                    }

                    input = input.trim().to_string();
                    if input.is_empty() {
                        continue;
                    }

                    match self.process_command(&input) {
                        Action::Output(output) => println!("{}", output),
                        Action::Exit => break,
                        Action::None => (),
                    }
                },
            }
        }

        println!("Bye!");
    }

    fn process_command(&mut self, command: &str) -> Action {
        // TODO: Split on all whitespace
        let mut args = command.split(" ").collect::<Vec<_>>();
        let command = args.remove(0);

        match command {
            "ls" => self.ls(args),
            "add" => self.add(args),
            "exit" => self.exit(args),
            "quit" => self.exit(args),
            _ => Action::Output("No such command!".to_string()),
        }
    }

    fn ls(&mut self, _: Vec<&str>) -> Action {
        let mut result = String::new();

        for book in self.storage.books() {
            result.push_str(&book.title);
        }

        Action::Output(result)
    }

    fn add(&mut self, _: Vec<&str>) -> Action {
        let date = match time::strftime(TIME_FORMAT, &time::now()) {
            Ok(date) => date,
            Err(_) => String::from("(unknown)"),
        };

        let content = text_from_editor();

        let entry = format!("\n{}\n\n{}", date, content);

        self.storage.add_entry(entry);

        Action::Output("Entry added".to_string())
    }

    fn exit(&mut self, _: Vec<&str>) -> Action {
        Action::Exit
    }
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

use std::num::Int;
use libc::*;

pub const NF_DROP: u32 = 0;
pub const NF_ACCEPT: u32 = 1;
pub const NF_STOLEN: u32 = 2;
pub const NF_QUEUE: u32 = 3;
pub const NF_REPEAT: u32 = 4;
pub const NF_STOP: u32 = 5;

#[repr(C)]
pub struct nfq_handle;

#[repr(C)]
pub struct nfq_q_handle;

#[repr(C)]
pub struct nfgenmsg;

#[repr(C)]
pub struct nfq_data;

#[repr(C)]
#[packed]
pub struct nfqnl_msg_packet_hdr {
    pub packet_id: uint32_t,
    pub hw_protocol: uint16_t,
    pub hook: uint8_t
}

impl nfqnl_msg_packet_hdr {
    pub fn id(&self) -> u32 { Int::from_be(self.packet_id) }
}

#[link(name="netfilter_queue")]
extern {
    pub static nfq_errno: c_int;

    // Library setup
    pub fn nfq_open() -> *mut nfq_handle;
    pub fn nfq_close(handle: *mut nfq_handle) -> c_int;
    pub fn nfq_bind_pf(handle: *mut nfq_handle, pf: uint16_t) -> c_int;
    pub fn nfq_unbind_pf(handle: *mut nfq_handle, pf: uint16_t) -> c_int;

    // Queue handling
    pub fn nfq_create_queue(handle: *mut nfq_handle,
                            num: uint16_t,
                            cb: extern "C" fn(h: *mut nfq_q_handle,
                                              nfmsg: *mut nfgenmsg,
                                              nfad: *mut nfq_data,
                                              data: *mut c_void) -> c_int,
                            data: *mut c_void) -> *mut nfq_q_handle;
    pub fn nfq_destroy_queue(handle: *mut nfq_q_handle) -> c_int;
    pub fn nfq_set_mode(handle: *mut nfq_q_handle,
                        mode: uint8_t,
                        range: uint32_t) -> c_int;
    pub fn nfq_set_queue_maxlen(handle: *mut nfq_q_handle,
                                queuelen: uint32_t) -> c_int;

    // Iterating through a queue
    pub fn nfq_fd(handle: *mut nfq_handle) -> c_int;
    pub fn nfq_handle_packet(handle: *mut nfq_handle,
                             buf: *mut c_char,
                             len: c_int) -> c_int;

    // Deciding on a verdict
    pub fn nfq_set_verdict(handle: *mut nfq_q_handle,
                           id: uint32_t,
                           verdict: uint32_t,
                           data_len: uint32_t,
                           buf: *const c_uchar) -> c_int;

    // Parsing the message
    pub fn nfq_get_msg_packet_hdr(nfad: *mut nfq_data) -> *const nfqnl_msg_packet_hdr;
}
<commit_msg>Remove use of deprecated std::num::Int<commit_after>#![allow(non_camel_case_types)]

use libc::*;

pub const NF_DROP: u32 = 0;
pub const NF_ACCEPT: u32 = 1;
pub const NF_STOLEN: u32 = 2;
pub const NF_QUEUE: u32 = 3;
pub const NF_REPEAT: u32 = 4;
pub const NF_STOP: u32 = 5;

#[repr(C)]
pub struct nfq_handle;

#[repr(C)]
pub struct nfq_q_handle;

#[repr(C)]
pub struct nfgenmsg;

#[repr(C)]
pub struct nfq_data;

#[repr(C)]
#[packed]
pub struct nfqnl_msg_packet_hdr {
    pub packet_id: uint32_t,
    pub hw_protocol: uint16_t,
    pub hook: uint8_t
}

impl nfqnl_msg_packet_hdr {
    pub fn id(&self) -> u32 { u32::from_be(self.packet_id) }
}

#[link(name="netfilter_queue")]
extern {
    pub static nfq_errno: c_int;

    // Library setup
    pub fn nfq_open() -> *mut nfq_handle;
    pub fn nfq_close(handle: *mut nfq_handle) -> c_int;
    pub fn nfq_bind_pf(handle: *mut nfq_handle, pf: uint16_t) -> c_int;
    pub fn nfq_unbind_pf(handle: *mut nfq_handle, pf: uint16_t) -> c_int;

    // Queue handling
    pub fn nfq_create_queue(handle: *mut nfq_handle,
                            num: uint16_t,
                            cb: extern "C" fn(h: *mut nfq_q_handle,
                                              nfmsg: *mut nfgenmsg,
                                              nfad: *mut nfq_data,
                                              data: *mut c_void) -> c_int,
                            data: *mut c_void) -> *mut nfq_q_handle;
    pub fn nfq_destroy_queue(handle: *mut nfq_q_handle) -> c_int;
    pub fn nfq_set_mode(handle: *mut nfq_q_handle,
                        mode: uint8_t,
                        range: uint32_t) -> c_int;
    pub fn nfq_set_queue_maxlen(handle: *mut nfq_q_handle,
                                queuelen: uint32_t) -> c_int;

    // Iterating through a queue
    pub fn nfq_fd(handle: *mut nfq_handle) -> c_int;
    pub fn nfq_handle_packet(handle: *mut nfq_handle,
                             buf: *mut c_char,
                             len: c_int) -> c_int;

    // Deciding on a verdict
    pub fn nfq_set_verdict(handle: *mut nfq_q_handle,
                           id: uint32_t,
                           verdict: uint32_t,
                           data_len: uint32_t,
                           buf: *const c_uchar) -> c_int;

    // Parsing the message
    pub fn nfq_get_msg_packet_hdr(nfad: *mut nfq_data) -> *const nfqnl_msg_packet_hdr;
}
<|endoftext|>


<commit_before>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 } $( else if $m1 { $h1 } )*
    }}
}

pub fn get(request: Request, mut response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request, response),
            path == "/ip" => origin(&request, response),
            path.starts_with("/status/") => status(path, response),
            path.starts_with("/test") => test(&request, response),
        ];
    }
}

fn index(request: &Request, mut response: Response) {
    let index = "<!DOCTYPE html>

            <link
                rel=\"icon\"
                href=\"http://investorintel.com/wp-content/uploads/2014/03/tin-can.jpg\"/>
            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(index.len() as u64));
    response.start().unwrap().write(index.as_bytes()).unwrap();
}

fn status(path: &str, mut response: Response) {
    // /status/xx
    // 0123456789
    let (_, param) = path.split_at(8);
    let code = match param.parse::<u16>() {
        Ok(status) => StatusCode::from_u16(status),
        Err(_) => StatusCode::BadRequest,
    };
    *response.status_mut() = code;
}

fn origin(request: &Request, mut response: Response) {
    let text = "Remote address decoding is not implemented yet";
    response.headers_mut().set(ContentType::plaintext());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}

fn test(request: &Request, mut response: Response) {
    let text = format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
                       request.remote_addr,
                       request.method,
                       request.version,
                       request.headers,
                       request.uri);
    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}
<commit_msg>Add 404 handler<commit_after>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 } $( else if $m1 { $h1 } )*
    }}
}

pub fn get(request: Request, mut response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request, response),
            path == "/ip" => origin(&request, response),
            path.starts_with("/status/") => status(path, response),
            path.starts_with("/test") => test(&request, response),
            true => notfound404(response),
        ];
    }
}

fn notfound404(mut response: Response) {
    let text = "<!DOCTYPE html>

            <title>404 Not Found</title>

Not Found

The requested URL was not found on the server.
        If you entered the URL manually please check your spelling and try again.

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}

fn index(request: &Request, mut response: Response) {
    let index = "<!DOCTYPE html>

            <link
                rel=\"icon\"
                href=\"http://investorintel.com/wp-content/uploads/2014/03/tin-can.jpg\"/>
            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(index.len() as u64));
    response.start().unwrap().write(index.as_bytes()).unwrap();
}

fn status(path: &str, mut response: Response) {
    // /status/xx
    // 0123456789
    let (_, param) = path.split_at(8);
    let code = match param.parse::<u16>() {
        Ok(status) => StatusCode::from_u16(status),
        Err(_) => StatusCode::BadRequest,
    };
    *response.status_mut() = code;
}

fn origin(request: &Request, mut response: Response) {
    let text = "Remote address decoding is not implemented yet";
    response.headers_mut().set(ContentType::plaintext());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}

fn test(request: &Request, mut response: Response) {
    let text = format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
                       request.remote_addr,
                       request.method,
                       request.version,
                       request.headers,
                       request.uri);
    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}
<|endoftext|>


<commit_before>use std::fmt;
use hyper::server::{Request, Response};

//#[get("/get")]
pub fn get(request: Request, mut response: Response) {
    let (remote_addr, _, headers, uri, version, payload) = request.deconstruct();
    println!("**  Handling GET {}", uri);
    println!("*** Incoming headers {:?}", headers);
}

// // #[get("/")]
// fn index() -> content::HTML<&'static str> {
//     content::HTML("<!DOCTYPE html>
//
//
//             <title>HTTPTIN</title>
//
//
//
HTTPTIN - HTTP tester in Rust and Rocket

//
//     ")
// }
//
// // #[get("/test")]
// fn test(data: IndexData) -> content::HTML<String> {
//     content::HTML(format!("<!DOCTYPE html>
//
//
//             <title>HTTPTIN></title>
//
//         {}
//     ",
//                           data))
// }

//#[get("/ip")]
fn origin() -> String {
    String::from("Remote address decoding is not implemented yet")
}

struct GetData {
    args: String,
    headers: String,
}

// //#[get("/status/")]
// pub fn status<'r>(code: u16) -> Response<'r> {
//     Response::build().status(Status::raw(code)).finalize()
// }
<commit_msg>Cleanups<commit_after>use hyper::server::{Request, Response};

pub fn get(request: Request, mut response: Response) {
    let (remote_addr, _, headers, uri, version, payload) = request.deconstruct();
    println!("**  Handling GET {}", uri);
    println!("*** Incoming headers {:?}", headers);
}

// // #[get("/")]
// fn index() -> content::HTML<&'static str> {
//     content::HTML("<!DOCTYPE html>
//
//
//             <title>HTTPTIN</title>
//
//
//
HTTPTIN - HTTP tester in Rust and Rocket

//
//     ")
// }
//
// // #[get("/test")]
// fn test(data: IndexData) -> content::HTML<String> {
//     content::HTML(format!("<!DOCTYPE html>
//
//
//             <title>HTTPTIN></title>
//
//         {}
//     ",
//                           data))
// }

//#[get("/ip")]
fn origin() -> String {
    String::from("Remote address decoding is not implemented yet")
}

struct GetData {
    args: String,
    headers: String,
}

// //#[get("/status/")]
// pub fn status<'r>(code: u16) -> Response<'r> {
//     Response::build().status(Status::raw(code)).finalize()
// }
<|endoftext|>