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

use self::Kind::{Length, Chunked, Eof};

/// Decoders to handle different Transfer-Encodings.
///
/// If a message body does not include a Transfer-Encoding, it *should*
/// include a Content-Length header.
#[derive(Debug, Clone)]
pub struct Decoder {
    kind: Kind,
}

impl Decoder {
    pub fn length(x: u64) -> Decoder {
        Decoder {
            kind: Kind::Length(x)
        }
    }

    pub fn chunked() -> Decoder {
        Decoder {
            kind: Kind::Chunked(None)
        }
    }

    pub fn eof() -> Decoder {
        Decoder {
            kind: Kind::Eof(false)
        }
    }
}

#[derive(Debug, Clone)]
enum Kind {
    /// A Reader used when a Content-Length header is passed with a positive integer.
    Length(u64),
    /// A Reader used when Transfer-Encoding is `chunked`.
    Chunked(Option<u64>),
    /// A Reader used for responses that don't indicate a length or chunked.
    ///
    /// Note: This should only used for `Response`s. It is illegal for a
    /// `Request` to be made with both `Content-Length` and
    /// `Transfer-Encoding: chunked` missing, as explained from the spec:
    ///
    /// > If a Transfer-Encoding header field is present in a response and
    /// > the chunked transfer coding is not the final encoding, the
    /// > message body length is determined by reading the connection until
    /// > it is closed by the server.  If a Transfer-Encoding header field
    /// > is present in a request and the chunked transfer coding is not
    /// > the final encoding, the message body length cannot be determined
    /// > reliably; the server MUST respond with the 400 (Bad Request)
    /// > status code and then close the connection.
    Eof(bool),
}

impl Decoder {
    pub fn is_eof(&self) -> bool {
        trace!("is_eof? {:?}", self);
        match self.kind {
            Length(0) |
            Chunked(Some(0)) |
            Eof(true) => true,
            _ => false
        }
    }
}

impl Decoder {
    pub fn decode<R: Read>(&mut self, body: &mut R, buf: &mut [u8]) -> io::Result<usize> {
        match self.kind {
            Length(ref mut remaining) => {
                trace!("Sized read, remaining={:?}", remaining);
                if *remaining == 0 {
                    Ok(0)
                } else {
                    let to_read = cmp::min(*remaining as usize, buf.len());
                    let num = try!(body.read(&mut buf[..to_read])) as u64;
                    trace!("Length read: {}", num);
                    if num > *remaining {
                        *remaining = 0;
                    } else if num == 0 {
                        return Err(io::Error::new(io::ErrorKind::Other, "early eof"));
                    } else {
                        *remaining -= num;
                    }
                    Ok(num as usize)
                }
            },
            Chunked(ref mut opt_remaining) => {
                let mut rem = match *opt_remaining {
                    Some(ref rem) => *rem,
                    // None means we don't know the size of the next chunk
                    None => try!(read_chunk_size(body))
                };
                trace!("Chunked read, remaining={:?}", rem);

                if rem == 0 {
                    *opt_remaining = Some(0);

                    // chunk of size 0 signals the end of the chunked stream
                    // if the 0 digit was missing from the stream, it would
                    // be an InvalidInput error instead.
                    trace!("end of chunked");
                    return Ok(0)
                }

                let to_read = cmp::min(rem as usize, buf.len());
                let count = try!(body.read(&mut buf[..to_read])) as u64;

                if count == 0 {
                    *opt_remaining = Some(0);
                    return Err(io::Error::new(io::ErrorKind::Other, "early eof"));
                }

                rem -= count;
                *opt_remaining = if rem > 0 {
                    Some(rem)
                } else {
                    try!(eat(body, b"\r\n"));
                    None
                };
                Ok(count as usize)
            },
            Eof(ref mut is_eof) => {
                match body.read(buf) {
                    Ok(0) => {
                        *is_eof = true;
                        Ok(0)
                    }
                    other => other
                }
            },
        }
    }
}

fn eat<R: Read>(rdr: &mut R, bytes: &[u8]) -> io::Result<()> {
    let mut buf = [0];
    for &b in bytes.iter() {
        match try!(rdr.read(&mut buf)) {
            1 if buf[0] == b => (),
            _ => return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                          "Invalid characters found")),
        }
    }
    Ok(())
}

/// Chunked chunks start with 1*HEXDIGIT, indicating the size of the chunk.
fn read_chunk_size<R: Read>(rdr: &mut R) -> io::Result<u64> {
    macro_rules! byte (
        ($rdr:ident) => ({
            let mut buf = [0];
            match try!($rdr.read(&mut buf)) {
                1 => buf[0],
                _ => return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                                  "Invalid chunk size line")),

            }
        })
    );
    let mut size = 0u64;
    let radix = 16;
    let mut in_ext = false;
    let mut in_chunk_size = true;
    loop {
        match byte!(rdr) {
            b@b'0'...b'9' if in_chunk_size => {
                size *= radix;
                size += (b - b'0') as u64;
            },
            b@b'a'...b'f' if in_chunk_size => {
                size *= radix;
                size += (b + 10 - b'a') as u64;
            },
            b@b'A'...b'F' if in_chunk_size => {
                size *= radix;
                size += (b + 10 - b'A') as u64;
            },
            b'\r' => {
                match byte!(rdr) {
                    b'\n' => break,
                    _ => return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                                  "Invalid chunk size line"))

                }
            },
            // If we weren't in the extension yet, the ";" signals its start
            b';' if !in_ext => {
                in_ext = true;
                in_chunk_size = false;
            },
            // "Linear white space" is ignored between the chunk size and the
            // extension separator token (";") due to the "implied *LWS rule".
            b'\t' | b' ' if !in_ext & !in_chunk_size => {},
            // LWS can follow the chunk size, but no more digits can come
            b'\t' | b' ' if in_chunk_size => in_chunk_size = false,
            // We allow any arbitrary octet once we are in the extension, since
            // they all get ignored anyway. According to the HTTP spec, valid
            // extensions would have a more strict syntax:
            //     (token ["=" (token | quoted-string)])
            // but we gain nothing by rejecting an otherwise valid chunk size.
            _ext if in_ext => {
                //TODO: chunk extension byte;
            },
            // Finally, if we aren't in the extension and we're reading any
            // other octet, the chunk size line is invalid!
            _ => {
                return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                         "Invalid chunk size line"));
            }
        }
    }
    trace!("chunk size={:?}", size);
    Ok(size)
}

#[cfg(test)]
mod tests {
    use std::error::Error;
    use std::io;
    use super::{Decoder, read_chunk_size};

    #[test]
    fn test_read_chunk_size() {
        fn read(s: &str, result: u64) {
            assert_eq!(read_chunk_size(&mut s.as_bytes()).unwrap(), result);
        }

        fn read_err(s: &str) {
            assert_eq!(read_chunk_size(&mut s.as_bytes()).unwrap_err().kind(),
                io::ErrorKind::InvalidInput);
        }

        read("1\r\n", 1);
        read("01\r\n", 1);
        read("0\r\n", 0);
        read("00\r\n", 0);
        read("A\r\n", 10);
        read("a\r\n", 10);
        read("Ff\r\n", 255);
        read("Ff   \r\n", 255);
        // Missing LF or CRLF
        read_err("F\rF");
        read_err("F");
        // Invalid hex digit
        read_err("X\r\n");
        read_err("1X\r\n");
        read_err("-\r\n");
        read_err("-1\r\n");
        // Acceptable (if not fully valid) extensions do not influence the size
        read("1;extension\r\n", 1);
        read("a;ext name=value\r\n", 10);
        read("1;extension;extension2\r\n", 1);
        read("1;;;  ;\r\n", 1);
        read("2; extension...\r\n", 2);
        read("3   ; extension=123\r\n", 3);
        read("3   ;\r\n", 3);
        read("3   ;   \r\n", 3);
        // Invalid extensions cause an error
        read_err("1 invalid extension\r\n");
        read_err("1 A\r\n");
        read_err("1;no CRLF");
    }

    #[test]
    fn test_read_sized_early_eof() {
        let mut bytes = &b"foo bar"[..];
        let mut decoder = Decoder::length(10);
        let mut buf = [0u8; 10];
        assert_eq!(decoder.decode(&mut bytes, &mut buf).unwrap(), 7);
        let e = decoder.decode(&mut bytes, &mut buf).unwrap_err();
        assert_eq!(e.kind(), io::ErrorKind::Other);
        assert_eq!(e.description(), "early eof");
    }

    #[test]
    fn test_read_chunked_early_eof() {
        let mut bytes = &b"\
            9\r\n\
            foo bar\
        "[..];
        let mut decoder = Decoder::chunked();
        let mut buf = [0u8; 10];
        assert_eq!(decoder.decode(&mut bytes, &mut buf).unwrap(), 7);
        let e = decoder.decode(&mut bytes, &mut buf).unwrap_err();
        assert_eq!(e.kind(), io::ErrorKind::Other);
        assert_eq!(e.description(), "early eof");
    }
}
<commit_msg>fix(http): make Chunked decoder resilient in an async world<commit_after>use std::{cmp, usize};
use std::io::{self, Read};

use self::Kind::{Length, Chunked, Eof};

/// Decoders to handle different Transfer-Encodings.
///
/// If a message body does not include a Transfer-Encoding, it *should*
/// include a Content-Length header.
#[derive(Debug, Clone)]
pub struct Decoder {
    kind: Kind,
}

impl Decoder {
    pub fn length(x: u64) -> Decoder {
        Decoder { kind: Kind::Length(x) }
    }

    pub fn chunked() -> Decoder {
        Decoder { kind: Kind::Chunked(ChunkedState::Size, 0) }
    }

    pub fn eof() -> Decoder {
        Decoder { kind: Kind::Eof(false) }
    }
}

#[derive(Debug, Clone)]
enum Kind {
    /// A Reader used when a Content-Length header is passed with a positive integer.
    Length(u64),
    /// A Reader used when Transfer-Encoding is `chunked`.
    Chunked(ChunkedState, u64),
    /// A Reader used for responses that don't indicate a length or chunked.
    ///
    /// Note: This should only used for `Response`s. It is illegal for a
    /// `Request` to be made with both `Content-Length` and
    /// `Transfer-Encoding: chunked` missing, as explained from the spec:
    ///
    /// > If a Transfer-Encoding header field is present in a response and
    /// > the chunked transfer coding is not the final encoding, the
    /// > message body length is determined by reading the connection until
    /// > it is closed by the server.  If a Transfer-Encoding header field
    /// > is present in a request and the chunked transfer coding is not
    /// > the final encoding, the message body length cannot be determined
    /// > reliably; the server MUST respond with the 400 (Bad Request)
    /// > status code and then close the connection.
    Eof(bool),
}

#[derive(Debug, PartialEq, Clone)]
enum ChunkedState {
    Size,
    SizeLws,
    Extension,
    SizeLf,
    Body,
    BodyCr,
    BodyLf,
    End,
}

impl Decoder {
    pub fn is_eof(&self) -> bool {
        trace!("is_eof? {:?}", self);
        match self.kind {
            Length(0) |
            Chunked(ChunkedState::End, _) |
            Eof(true) => true,
            _ => false,
        }
    }
}

impl Decoder {
    pub fn decode<R: Read>(&mut self, body: &mut R, buf: &mut [u8]) -> io::Result<usize> {
        match self.kind {
            Length(ref mut remaining) => {
                trace!("Sized read, remaining={:?}", remaining);
                if *remaining == 0 {
                    Ok(0)
                } else {
                    let to_read = cmp::min(*remaining as usize, buf.len());
                    let num = try!(body.read(&mut buf[..to_read])) as u64;
                    trace!("Length read: {}", num);
                    if num > *remaining {
                        *remaining = 0;
                    } else if num == 0 {
                        return Err(io::Error::new(io::ErrorKind::Other, "early eof"));
                    } else {
                        *remaining -= num;
                    }
                    Ok(num as usize)
                }
            }
            Chunked(ref mut state, ref mut size) => {
                loop {
                    let mut read = 0;
                    // advances the chunked state
                    *state = try!(state.step(body, size, buf, &mut read));
                    if *state == ChunkedState::End {
                        trace!("end of chunked");
                        return Ok(0);
                    }
                    if read > 0 {
                        return Ok(read);
                    }
                }
            }
            Eof(ref mut is_eof) => {
                match body.read(buf) {
                    Ok(0) => {
                        *is_eof = true;
                        Ok(0)
                    }
                    other => other,
                }
            }
        }
    }
}

macro_rules! byte (
    ($rdr:ident) => ({
        let mut buf = [0];
        match try!($rdr.read(&mut buf)) {
            1 => buf[0],
            _ => return Err(io::Error::new(io::ErrorKind::UnexpectedEof,
                                           "Unexpected eof during chunk size line")),
        }
    })
);

impl ChunkedState {
    fn step<R: Read>(&self,
                     body: &mut R,
                     size: &mut u64,
                     buf: &mut [u8],
                     read: &mut usize)
                     -> io::Result<ChunkedState> {
        use self::ChunkedState::*;
        Ok(match *self {
            Size => try!(ChunkedState::read_size(body, size)),
            SizeLws => try!(ChunkedState::read_size_lws(body)),
            Extension => try!(ChunkedState::read_extension(body)),
            SizeLf => try!(ChunkedState::read_size_lf(body, size)),
            Body => try!(ChunkedState::read_body(body, size, buf, read)),
            BodyCr => try!(ChunkedState::read_body_cr(body)),
            BodyLf => try!(ChunkedState::read_body_lf(body)),
            End => ChunkedState::End,
        })
    }
    fn read_size<R: Read>(rdr: &mut R, size: &mut u64) -> io::Result<ChunkedState> {
        trace!("Read size");
        let radix = 16;
        match byte!(rdr) {
            b @ b'0'...b'9' => {
                *size *= radix;
                *size += (b - b'0') as u64;
            }
            b @ b'a'...b'f' => {
                *size *= radix;
                *size += (b + 10 - b'a') as u64;
            }
            b @ b'A'...b'F' => {
                *size *= radix;
                *size += (b + 10 - b'A') as u64;
            }
            b'\t' | b' ' => return Ok(ChunkedState::SizeLws),
            b';' => return Ok(ChunkedState::Extension),
            b'\r' => return Ok(ChunkedState::SizeLf),
            _ => {
                return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                          "Invalid chunk size line: Invalid Size"));
            }
        }
        Ok(ChunkedState::Size)
    }
    fn read_size_lws<R: Read>(rdr: &mut R) -> io::Result<ChunkedState> {
        trace!("read_size_lws");
        match byte!(rdr) {
            // LWS can follow the chunk size, but no more digits can come
            b'\t' | b' ' => Ok(ChunkedState::SizeLws),
            b';' => Ok(ChunkedState::Extension),
            b'\r' => return Ok(ChunkedState::SizeLf),
            _ => {
                Err(io::Error::new(io::ErrorKind::InvalidInput,
                                   "Invalid chunk size linear white space"))
            }
        }
    }
    fn read_extension<R: Read>(rdr: &mut R) -> io::Result<ChunkedState> {
        trace!("read_extension");
        match byte!(rdr) {
            b'\r' => return Ok(ChunkedState::SizeLf),
            _ => return Ok(ChunkedState::Extension), // no supported extensions
        }
    }
    fn read_size_lf<R: Read>(rdr: &mut R, size: &mut u64) -> io::Result<ChunkedState> {
        trace!("Chunk size is {:?}", size);
        match byte!(rdr) {
            b'\n' if *size > 0 => Ok(ChunkedState::Body),
            b'\n' if *size == 0 => Ok(ChunkedState::End),
            _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk size LF")),
        }
    }
    fn read_body<R: Read>(rdr: &mut R,
                          rem: &mut u64,
                          buf: &mut [u8],
                          read: &mut usize)
                          -> io::Result<ChunkedState> {
        trace!("Chunked read, remaining={:?}", rem);

        // cap remaining bytes at the max capacity of usize
        let rem_cap = match *rem {
            r if r > usize::MAX as u64 => usize::MAX,
            r => r as usize,
        };

        let to_read = cmp::min(rem_cap, buf.len());
        let count = try!(rdr.read(&mut buf[..to_read]));

        trace!("to_read = {}", to_read);
        trace!("count = {}", count);

        if count == 0 {
            *rem = 0;
            return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "early eof"));
        }

        *rem -= count as u64;
        *read = count;

        if *rem > 0 {
            Ok(ChunkedState::Body)
        } else {
            Ok(ChunkedState::BodyCr)
        }
    }
    fn read_body_cr<R: Read>(rdr: &mut R) -> io::Result<ChunkedState> {
        match byte!(rdr) {
            b'\r' => Ok(ChunkedState::BodyLf),
            _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body CR")),
        }
    }
    fn read_body_lf<R: Read>(rdr: &mut R) -> io::Result<ChunkedState> {
        match byte!(rdr) {
            b'\n' => Ok(ChunkedState::Size),
            _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body LF")),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::error::Error;
    use std::io;
    use std::io::Write;
    use super::Decoder;
    use super::ChunkedState;
    use mock::Async;

    #[test]
    fn test_read_chunk_size() {
        use std::io::ErrorKind::{UnexpectedEof, InvalidInput};

        fn read(s: &str) -> u64 {
            let mut state = ChunkedState::Size;
            let mut rdr = &mut s.as_bytes();
            let mut size = 0;
            let mut count = 0;
            loop {
                let mut buf = [0u8; 10];
                let result = state.step(&mut rdr, &mut size, &mut buf, &mut count);
                let desc = format!("read_size failed for {:?}", s);
                state = result.expect(desc.as_str());
                trace!("State {:?}", state);
                if state == ChunkedState::Body || state == ChunkedState::End {
                    break;
                }
            }
            size
        }

        fn read_err(s: &str, expected_err: io::ErrorKind) {
            let mut state = ChunkedState::Size;
            let mut rdr = &mut s.as_bytes();
            let mut size = 0;
            let mut count = 0;
            loop {
                let mut buf = [0u8; 10];
                let result = state.step(&mut rdr, &mut size, &mut buf, &mut count);
                state = match result {
                    Ok(s) => s,
                    Err(e) => {
                        assert!(expected_err == e.kind(), "Reading {:?}, expected {:?}, but got {:?}",
                                                          s, expected_err, e.kind());
                        return;
                    }
                };
                trace!("State {:?}", state);
                if state == ChunkedState::Body || state == ChunkedState::End {
                    panic!(format!("Was Ok. Expected Err for {:?}", s));
                }
            }
        }

        assert_eq!(1, read("1\r\n"));
        assert_eq!(1, read("01\r\n"));
        assert_eq!(0, read("0\r\n"));
        assert_eq!(0, read("00\r\n"));
        assert_eq!(10, read("A\r\n"));
        assert_eq!(10, read("a\r\n"));
        assert_eq!(255, read("Ff\r\n"));
        assert_eq!(255, read("Ff   \r\n"));
        // Missing LF or CRLF
        read_err("F\rF", InvalidInput);
        read_err("F", UnexpectedEof);
        // Invalid hex digit
        read_err("X\r\n", InvalidInput);
        read_err("1X\r\n", InvalidInput);
        read_err("-\r\n", InvalidInput);
        read_err("-1\r\n", InvalidInput);
        // Acceptable (if not fully valid) extensions do not influence the size
        assert_eq!(1, read("1;extension\r\n"));
        assert_eq!(10, read("a;ext name=value\r\n"));
        assert_eq!(1, read("1;extension;extension2\r\n"));
        assert_eq!(1, read("1;;;  ;\r\n"));
        assert_eq!(2, read("2; extension...\r\n"));
        assert_eq!(3, read("3   ; extension=123\r\n"));
        assert_eq!(3, read("3   ;\r\n"));
        assert_eq!(3, read("3   ;   \r\n"));
        // Invalid extensions cause an error
        read_err("1 invalid extension\r\n", InvalidInput);
        read_err("1 A\r\n", InvalidInput);
        read_err("1;no CRLF", UnexpectedEof);
    }

    #[test]
    fn test_read_sized_early_eof() {
        let mut bytes = &b"foo bar"[..];
        let mut decoder = Decoder::length(10);
        let mut buf = [0u8; 10];
        assert_eq!(decoder.decode(&mut bytes, &mut buf).unwrap(), 7);
        let e = decoder.decode(&mut bytes, &mut buf).unwrap_err();
        assert_eq!(e.kind(), io::ErrorKind::Other);
        assert_eq!(e.description(), "early eof");
    }

    #[test]
    fn test_read_chunked_early_eof() {
        let mut bytes = &b"\
            9\r\n\
            foo bar\
        "[..];
        let mut decoder = Decoder::chunked();
        let mut buf = [0u8; 10];
        assert_eq!(decoder.decode(&mut bytes, &mut buf).unwrap(), 7);
        let e = decoder.decode(&mut bytes, &mut buf).unwrap_err();
        assert_eq!(e.kind(), io::ErrorKind::UnexpectedEof);
        assert_eq!(e.description(), "early eof");
    }

    #[test]
    fn test_read_chunked_single_read() {
        let content = b"10\r\n1234567890abcdef\r\n0\r\n";
        let mut mock_buf = io::Cursor::new(content);
        let mut buf = [0u8; 16];
        let count = Decoder::chunked().decode(&mut mock_buf, &mut buf).expect("decode");
        assert_eq!(16, count);
        let result = String::from_utf8(buf.to_vec()).expect("decode String");
        assert_eq!("1234567890abcdef", &result);
    }

    #[test]
    fn test_read_chunked_after_eof() {
        let content = b"10\r\n1234567890abcdef\r\n0\r\n";
        let mut mock_buf = io::Cursor::new(content);
        let mut buf = [0u8; 50];
        let mut decoder = Decoder::chunked();

        // normal read
        let count = decoder.decode(&mut mock_buf, &mut buf).expect("decode");
        assert_eq!(16, count);
        let result = String::from_utf8(buf[0..count].to_vec()).expect("decode String");
        assert_eq!("1234567890abcdef", &result);

        // eof read
        let count = decoder.decode(&mut mock_buf, &mut buf).expect("decode");
        assert_eq!(0, count);

        // ensure read after eof also returns eof
        let count = decoder.decode(&mut mock_buf, &mut buf).expect("decode");
        assert_eq!(0, count);
    }

    // perform an async read using a custom buffer size and causing a blocking
    // read at the specified byte
    fn read_async(mut decoder: Decoder,
                  content: &[u8],
                  block_at: usize,
                  read_buffer_size: usize)
                  -> String {
        let content_len = content.len();
        let mock_buf = io::Cursor::new(content.clone());
        let mut ins = Async::new(mock_buf, block_at);
        let mut outs = vec![];
        loop {
            let mut buf = vec![0; read_buffer_size];
            match decoder.decode(&mut ins, buf.as_mut_slice()) {
                Ok(0) => break,
                Ok(i) => outs.write(&buf[0..i]).expect("write buffer"),
                Err(e) => {
                    if e.kind() != io::ErrorKind::WouldBlock {
                        break;
                    }
                    ins.block_in(content_len); // we only block once
                    0 as usize
                }
            };
        }
        String::from_utf8(outs).expect("decode String")
    }

    // iterate over the different ways that this async read could go.
    // tests every combination of buffer size that is passed in, with a blocking
    // read at each byte along the content - The shotgun approach
    fn all_async_cases(content: &str, expected: &str, decoder: Decoder) {
        let content_len = content.len();
        for block_at in 0..content_len {
            for read_buffer_size in 1..content_len {
                let actual = read_async(decoder.clone(),
                                        content.as_bytes(),
                                        block_at,
                                        read_buffer_size);
                assert_eq!(expected,
                    &actual,
                    "Failed async. Blocking at {} with read buffer size {}",
                    block_at,
                    read_buffer_size);
            }
        }
    }

    #[test]
    fn test_read_length_async() {
        let content = "foobar";
        all_async_cases(content, content, Decoder::length(content.len() as u64));
    }

    #[test]
    fn test_read_chunked_async() {
        let content = "3\r\nfoo\r\n3\r\nbar\r\n0\r\n";
        let expected = "foobar";
        all_async_cases(content, expected, Decoder::chunked());
    }

    #[test]
    fn test_read_eof_async() {
        let content = "foobar";
        all_async_cases(content, content, Decoder::eof());
    }

}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![macro_escape]

/// Entry point of task panic, for details, see std::macros
#[macro_export]
macro_rules! panic {
    () => (
        panic!("{}", "explicit panic")
    );
    ($msg:expr) => ({
        static _MSG_FILE_LINE: (&'static str, &'static str, uint) = ($msg, file!(), line!());
        ::core::panicking::panic(&_MSG_FILE_LINE)
    });
    ($fmt:expr, $($arg:tt)*) => ({
        // a closure can't have return type !, so we need a full
        // function to pass to format_args!, *and* we need the
        // file and line numbers right here; so an inner bare fn
        // is our only choice.
        //
        // LLVM doesn't tend to inline this, presumably because begin_unwind_fmt
        // is #[cold] and #[inline(never)] and because this is flagged as cold
        // as returning !. We really do want this to be inlined, however,
        // because it's just a tiny wrapper. Small wins (156K to 149K in size)
        // were seen when forcing this to be inlined, and that number just goes
        // up with the number of calls to panic!()
        //
        // The leading _'s are to avoid dead code warnings if this is
        // used inside a dead function. Just `#[allow(dead_code)]` is
        // insufficient, since the user may have
        // `#[forbid(dead_code)]` and which cannot be overridden.
        #[inline(always)]
        fn _run_fmt(fmt: &::std::fmt::Arguments) -> ! {
            static _FILE_LINE: (&'static str, uint) = (file!(), line!());
            ::core::panicking::panic_fmt(fmt, &_FILE_LINE)
        }
        format_args!(_run_fmt, $fmt, $($arg)*)
    });
}

/// Runtime assertion, for details see std::macros
#[macro_export]
macro_rules! assert {
    ($cond:expr) => (
        if !$cond {
            panic!(concat!("assertion failed: ", stringify!($cond)))
        }
    );
    ($cond:expr, $($arg:tt)*) => (
        if !$cond {
            panic!($($arg)*)
        }
    );
}

/// Runtime assertion, only without `--cfg ndebug`
#[macro_export]
macro_rules! debug_assert {
    ($(a:tt)*) => ({
        if cfg!(not(ndebug)) {
            assert!($($a)*);
        }
    })
}

/// Runtime assertion for equality, for details see std::macros
#[macro_export]
macro_rules! assert_eq {
    ($cond1:expr, $cond2:expr) => ({
        let c1 = $cond1;
        let c2 = $cond2;
        if c1 != c2 || c2 != c1 {
            panic!("expressions not equal, left: {}, right: {}", c1, c2);
        }
    })
}

/// Runtime assertion for equality, only without `--cfg ndebug`
#[macro_export]
macro_rules! debug_assert_eq {
    ($($a:tt)*) => ({
        if cfg!(not(ndebug)) {
            assert_eq!($($a)*);
        }
    })
}

/// Runtime assertion, disableable at compile time
#[macro_export]
macro_rules! debug_assert {
    ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
}

/// Short circuiting evaluation on Err
#[macro_export]
macro_rules! try {
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
}

/// Writing a formatted string into a writer
#[macro_export]
macro_rules! write {
    ($dst:expr, $($arg:tt)*) => ({
        let dst = &mut *$dst;
        format_args!(|args| { dst.write_fmt(args) }, $($arg)*)
    })
}

/// Writing a formatted string plus a newline into a writer
#[macro_export]
macro_rules! writeln {
    ($dst:expr, $fmt:expr $($arg:tt)*) => (
        write!($dst, concat!($fmt, "\n") $($arg)*)
    )
}

#[macro_export]
macro_rules! unreachable { () => (panic!("unreachable code")) }

<commit_msg>core: Removed a shadowed, unused definition of `debug_assert!`.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![macro_escape]

/// Entry point of task panic, for details, see std::macros
#[macro_export]
macro_rules! panic {
    () => (
        panic!("{}", "explicit panic")
    );
    ($msg:expr) => ({
        static _MSG_FILE_LINE: (&'static str, &'static str, uint) = ($msg, file!(), line!());
        ::core::panicking::panic(&_MSG_FILE_LINE)
    });
    ($fmt:expr, $($arg:tt)*) => ({
        // a closure can't have return type !, so we need a full
        // function to pass to format_args!, *and* we need the
        // file and line numbers right here; so an inner bare fn
        // is our only choice.
        //
        // LLVM doesn't tend to inline this, presumably because begin_unwind_fmt
        // is #[cold] and #[inline(never)] and because this is flagged as cold
        // as returning !. We really do want this to be inlined, however,
        // because it's just a tiny wrapper. Small wins (156K to 149K in size)
        // were seen when forcing this to be inlined, and that number just goes
        // up with the number of calls to panic!()
        //
        // The leading _'s are to avoid dead code warnings if this is
        // used inside a dead function. Just `#[allow(dead_code)]` is
        // insufficient, since the user may have
        // `#[forbid(dead_code)]` and which cannot be overridden.
        #[inline(always)]
        fn _run_fmt(fmt: &::std::fmt::Arguments) -> ! {
            static _FILE_LINE: (&'static str, uint) = (file!(), line!());
            ::core::panicking::panic_fmt(fmt, &_FILE_LINE)
        }
        format_args!(_run_fmt, $fmt, $($arg)*)
    });
}

/// Runtime assertion, for details see std::macros
#[macro_export]
macro_rules! assert {
    ($cond:expr) => (
        if !$cond {
            panic!(concat!("assertion failed: ", stringify!($cond)))
        }
    );
    ($cond:expr, $($arg:tt)*) => (
        if !$cond {
            panic!($($arg)*)
        }
    );
}

/// Runtime assertion for equality, for details see std::macros
#[macro_export]
macro_rules! assert_eq {
    ($cond1:expr, $cond2:expr) => ({
        let c1 = $cond1;
        let c2 = $cond2;
        if c1 != c2 || c2 != c1 {
            panic!("expressions not equal, left: {}, right: {}", c1, c2);
        }
    })
}

/// Runtime assertion for equality, only without `--cfg ndebug`
#[macro_export]
macro_rules! debug_assert_eq {
    ($($a:tt)*) => ({
        if cfg!(not(ndebug)) {
            assert_eq!($($a)*);
        }
    })
}

/// Runtime assertion, disableable at compile time with `--cfg ndebug`
#[macro_export]
macro_rules! debug_assert {
    ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
}

/// Short circuiting evaluation on Err
#[macro_export]
macro_rules! try {
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
}

/// Writing a formatted string into a writer
#[macro_export]
macro_rules! write {
    ($dst:expr, $($arg:tt)*) => ({
        let dst = &mut *$dst;
        format_args!(|args| { dst.write_fmt(args) }, $($arg)*)
    })
}

/// Writing a formatted string plus a newline into a writer
#[macro_export]
macro_rules! writeln {
    ($dst:expr, $fmt:expr $($arg:tt)*) => (
        write!($dst, concat!($fmt, "\n") $($arg)*)
    )
}

#[macro_export]
macro_rules! unreachable { () => (panic!("unreachable code")) }

<|endoftext|>


<commit_before><commit_msg>Remove ObjectStream::new()<commit_after><|endoftext|>


<commit_before><commit_msg>Add test for #28514<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

pub use inner::C;

mod inner {
    trait A {
        fn a(&self) { }
    }

    pub trait B {
        fn b(&self) { }
    }

    pub trait C: A + B { //~ ERROR private trait in public interface
                         //~^ WARN will become a hard error
        fn c(&self) { }
    }

    impl A for i32 {}
    impl B for i32 {}
    impl C for i32 {}

}

fn main() {
    // A is private
    // B is pub, not reexported
    // C : A + B is pub, reexported

    // 0.a(); // can't call
    // 0.b(); // can't call
    0.c(); // ok

    C::a(&0); // can call
    C::b(&0); // can call
    C::c(&0); // ok
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;

use glium::Surface;
use glium::glutin;

mod support;

#[derive(Copy, Clone, Debug)]
struct PerInstance {
    pub id: u32,
    pub w_position: (f32, f32, f32),
    pub color: (f32, f32, f32),
}
implement_vertex!(PerInstance, id, w_position, color);

fn main() {
    use glium::DisplayBuild;

    // building the display, ie. the main object
    let display = glutin::WindowBuilder::new()
        .with_depth_buffer(24)
        .build_glium()
        .unwrap();

    // building the vertex and index buffers
    let vertex_buffer = support::load_wavefront(&display, include_bytes!("support/teapot.obj"));

    // the program
    let program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in uint id;
                in vec3 w_position;
                in vec3 color;
                in vec3 position;
                in vec3 normal;
                out vec3 v_normal;
                out vec3 v_color;

                void main() {
                    v_normal = normal;
                    v_color = color;
                    gl_Position = persp_matrix * view_matrix * vec4(position * 0.005 + w_position, 1.0);
                }
            ",

            fragment: "
                #version 140

                in vec3 v_normal;
                in vec3 v_color;
                out vec4 f_color;

                const vec3 LIGHT = vec3(-0.2, 0.8, 0.1);

                void main() {
                    float lum = max(dot(normalize(v_normal), normalize(LIGHT)), 0.0);
                    vec3 color = (0.3 + 0.7 * lum) * v_color;
                    f_color = vec4(color, 1.0);
                }
            ",
        },
    ).unwrap();

    // the picking program
    let picking_program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in uint id;
                in vec3 w_position;
                in vec3 color;
                in vec3 position;
                in vec3 normal;
                flat out uint v_id;

                void main() {
                    v_id = id;
                    gl_Position = persp_matrix * view_matrix * vec4(position * 0.005 + w_position, 1.0);
                }
            ",

            fragment: "
                #version 140

                flat in uint v_id;
                out uint f_id;

                void main() {
                    f_id = v_id;
                }
            ",
        },
    ).unwrap();

    let mut camera = support::camera::CameraState::new();
    camera.set_position((0.0, 0.0, 1.5));
    camera.set_direction((0.0, 0.0, 1.0));

    //id's must be unique and != 0
    let mut per_instance = vec![
        PerInstance { id: 1, w_position: (-1.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
        PerInstance { id: 2, w_position: ( 0.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
        PerInstance { id: 3, w_position: ( 1.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
    ];
    per_instance.sort_by(|a, b| a.id.cmp(&b.id));
    let original = per_instance.clone();

    let mut picking_attachments: Option<(glium::texture::UnsignedTexture2d, glium::framebuffer::DepthRenderBuffer)> = None;
    let picking_pbo: glium::texture::pixel_buffer::PixelBuffer<u32>
        = glium::texture::pixel_buffer::PixelBuffer::new_empty(&display, 1);

    let mut cursor_position: Option<(i32, i32)> = None;

    // the main loop
    support::start_loop(|| {
        camera.update();

        // determing which object has been picked at the previous frame
        let picked_object = {
            let data = picking_pbo.read().map(|d| d[0]).unwrap_or(0);
            if data != 0 {
                per_instance.binary_search_by(|x| x.id.cmp(&data)).ok()
            } else {
                None
            }
        };

        per_instance = original.clone();
        if let Some(index) = picked_object {
            per_instance[index as usize] = PerInstance {
                id: per_instance[index as usize].id,
                w_position: per_instance[index as usize].w_position,
                color: (0.0, 1.0, 0.0)
            };
        }

        // building the uniforms
        let uniforms = uniform! {
            persp_matrix: camera.get_perspective(),
            view_matrix: camera.get_view(),
        };

        // draw parameters
        let params = glium::DrawParameters {
            depth: glium::Depth {
                test: glium::DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };

        let per_instance_buffer = glium::vertex::VertexBuffer::new(&display, &per_instance).unwrap();

        // drawing a frame
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 0.0, 0.0), 1.0);

        //update picking texture
        if picking_attachments.is_none() || (
            picking_attachments.as_ref().unwrap().0.get_width(),
            picking_attachments.as_ref().unwrap().0.get_height().unwrap()
        ) != target.get_dimensions() {
            let (width, height) = target.get_dimensions();
            picking_attachments = Some((
                glium::texture::UnsignedTexture2d::empty_with_format(
                    &display,
                    glium::texture::UncompressedUintFormat::U32,
                    glium::texture::MipmapsOption::NoMipmap,
                    width, height,
                ).unwrap(),
                glium::framebuffer::DepthRenderBuffer::new(
                    &display,
                    glium::texture::DepthFormat::F32,
                    width, height,
                ).unwrap()
            ))
        }

        // drawing the models and pass the picking texture
        if let Some((ref picking_texture, ref depth_buffer)) = picking_attachments {
            //clearing the picking texture
            picking_texture.main_level().first_layer().into_image(None).unwrap().raw_clear_buffer([0u32, 0, 0, 0]);

            let mut picking_target = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&display, picking_texture, depth_buffer).unwrap();
            picking_target.clear_depth(1.0);
            picking_target.draw((&vertex_buffer, per_instance_buffer.per_instance().unwrap()),
                        &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                        &picking_program, &uniforms, &params).unwrap();
        }
        target.draw((&vertex_buffer, per_instance_buffer.per_instance().unwrap()),
                    &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                    &program, &uniforms, &params).unwrap();
        target.finish().unwrap();

        // committing into the picking pbo
        if let (Some(cursor), Some(&(ref picking_texture, _))) = (cursor_position, picking_attachments.as_ref()) {
            let read_target = glium::Rect {
                left: cursor.0 as u32,
                bottom: picking_texture.get_height().unwrap() - cursor.1 as u32,
                width: 1,
                height: 1,
            };

            if read_target.left < picking_texture.get_width()
            && read_target.bottom < picking_texture.get_height().unwrap() {
                picking_texture.main_level()
                    .first_layer()
                    .into_image(None).unwrap()
                    .raw_read_to_pixel_buffer(&read_target, &picking_pbo);
            } else {
                picking_pbo.write(&[0]);
            }
        } else {
            picking_pbo.write(&[0]);
        }

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return support::Action::Stop,
                glutin::Event::MouseMoved(m) => cursor_position = Some(m),
                ev => camera.process_input(&ev),
            }
        }

        support::Action::Continue
    });
}
<commit_msg>fixed the off by one error for the x axis<commit_after>#[macro_use]
extern crate glium;

use glium::Surface;
use glium::glutin;

mod support;

#[derive(Copy, Clone, Debug)]
struct PerInstance {
    pub id: u32,
    pub w_position: (f32, f32, f32),
    pub color: (f32, f32, f32),
}
implement_vertex!(PerInstance, id, w_position, color);

fn main() {
    use glium::DisplayBuild;

    // building the display, ie. the main object
    let display = glutin::WindowBuilder::new()
        .with_depth_buffer(24)
        .build_glium()
        .unwrap();

    // building the vertex and index buffers
    let vertex_buffer = support::load_wavefront(&display, include_bytes!("support/teapot.obj"));

    // the program
    let program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in uint id;
                in vec3 w_position;
                in vec3 color;
                in vec3 position;
                in vec3 normal;
                out vec3 v_normal;
                out vec3 v_color;

                void main() {
                    v_normal = normal;
                    v_color = color;
                    gl_Position = persp_matrix * view_matrix * vec4(position * 0.005 + w_position, 1.0);
                }
            ",

            fragment: "
                #version 140

                in vec3 v_normal;
                in vec3 v_color;
                out vec4 f_color;

                const vec3 LIGHT = vec3(-0.2, 0.8, 0.1);

                void main() {
                    float lum = max(dot(normalize(v_normal), normalize(LIGHT)), 0.0);
                    vec3 color = (0.3 + 0.7 * lum) * v_color;
                    f_color = vec4(color, 1.0);
                }
            ",
        },
    ).unwrap();

    // the picking program
    let picking_program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in uint id;
                in vec3 w_position;
                in vec3 color;
                in vec3 position;
                in vec3 normal;
                flat out uint v_id;

                void main() {
                    v_id = id;
                    gl_Position = persp_matrix * view_matrix * vec4(position * 0.005 + w_position, 1.0);
                }
            ",

            fragment: "
                #version 140

                flat in uint v_id;
                out uint f_id;

                void main() {
                    f_id = v_id;
                }
            ",
        },
    ).unwrap();

    let mut camera = support::camera::CameraState::new();
    camera.set_position((0.0, 0.0, 1.5));
    camera.set_direction((0.0, 0.0, 1.0));

    //id's must be unique and != 0
    let mut per_instance = vec![
        PerInstance { id: 1, w_position: (-1.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
        PerInstance { id: 2, w_position: ( 0.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
        PerInstance { id: 3, w_position: ( 1.0, 0.0, 0.0), color: (1.0, 0.0, 0.0)},
    ];
    per_instance.sort_by(|a, b| a.id.cmp(&b.id));
    let original = per_instance.clone();

    let mut picking_attachments: Option<(glium::texture::UnsignedTexture2d, glium::framebuffer::DepthRenderBuffer)> = None;
    let picking_pbo: glium::texture::pixel_buffer::PixelBuffer<u32>
        = glium::texture::pixel_buffer::PixelBuffer::new_empty(&display, 1);

    let mut cursor_position: Option<(i32, i32)> = None;

    // the main loop
    support::start_loop(|| {
        camera.update();

        // determing which object has been picked at the previous frame
        let picked_object = {
            let data = picking_pbo.read().map(|d| d[0]).unwrap_or(0);
            if data != 0 {
                per_instance.binary_search_by(|x| x.id.cmp(&data)).ok()
            } else {
                None
            }
        };

        per_instance = original.clone();
        if let Some(index) = picked_object {
            per_instance[index as usize] = PerInstance {
                id: per_instance[index as usize].id,
                w_position: per_instance[index as usize].w_position,
                color: (0.0, 1.0, 0.0)
            };
        }

        // building the uniforms
        let uniforms = uniform! {
            persp_matrix: camera.get_perspective(),
            view_matrix: camera.get_view(),
        };

        // draw parameters
        let params = glium::DrawParameters {
            depth: glium::Depth {
                test: glium::DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };

        let per_instance_buffer = glium::vertex::VertexBuffer::new(&display, &per_instance).unwrap();

        // drawing a frame
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 0.0, 0.0), 1.0);

        //update picking texture
        if picking_attachments.is_none() || (
            picking_attachments.as_ref().unwrap().0.get_width(),
            picking_attachments.as_ref().unwrap().0.get_height().unwrap()
        ) != target.get_dimensions() {
            let (width, height) = target.get_dimensions();
            picking_attachments = Some((
                glium::texture::UnsignedTexture2d::empty_with_format(
                    &display,
                    glium::texture::UncompressedUintFormat::U32,
                    glium::texture::MipmapsOption::NoMipmap,
                    width, height,
                ).unwrap(),
                glium::framebuffer::DepthRenderBuffer::new(
                    &display,
                    glium::texture::DepthFormat::F32,
                    width, height,
                ).unwrap()
            ))
        }

        // drawing the models and pass the picking texture
        if let Some((ref picking_texture, ref depth_buffer)) = picking_attachments {
            //clearing the picking texture
            picking_texture.main_level().first_layer().into_image(None).unwrap().raw_clear_buffer([0u32, 0, 0, 0]);

            let mut picking_target = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&display, picking_texture, depth_buffer).unwrap();
            picking_target.clear_depth(1.0);
            picking_target.draw((&vertex_buffer, per_instance_buffer.per_instance().unwrap()),
                        &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                        &picking_program, &uniforms, &params).unwrap();
        }
        target.draw((&vertex_buffer, per_instance_buffer.per_instance().unwrap()),
                    &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                    &program, &uniforms, &params).unwrap();
        target.finish().unwrap();

        // committing into the picking pbo
        if let (Some(cursor), Some(&(ref picking_texture, _))) = (cursor_position, picking_attachments.as_ref()) {
            let read_target = glium::Rect {
                left: cursor.0 as u32 - 1,
                bottom: picking_texture.get_height().unwrap() - cursor.1 as u32,
                width: 1,
                height: 1,
            };

            if read_target.left < picking_texture.get_width()
            && read_target.bottom < picking_texture.get_height().unwrap() {
                picking_texture.main_level()
                    .first_layer()
                    .into_image(None).unwrap()
                    .raw_read_to_pixel_buffer(&read_target, &picking_pbo);
            } else {
                picking_pbo.write(&[0]);
            }
        } else {
            picking_pbo.write(&[0]);
        }

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return support::Action::Stop,
                glutin::Event::MouseMoved(m) => cursor_position = Some(m),
                ev => camera.process_input(&ev),
            }
        }

        support::Action::Continue
    });
}
<|endoftext|>


<commit_before><commit_msg>Remove comment regarding vertex stage inputs after clarification<commit_after><|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::mem;
use rustc_data_structures::blake2b::Blake2bHasher;
use rustc::ty::util::ArchIndependentHasher;
use ich::Fingerprint;

#[derive(Debug)]
pub struct IchHasher {
    state: ArchIndependentHasher<Blake2bHasher>,
    bytes_hashed: u64,
}

impl IchHasher {
    pub fn new() -> IchHasher {
        let hash_size = mem::size_of::<Fingerprint>();
        IchHasher {
            state: ArchIndependentHasher::new(Blake2bHasher::new(hash_size, &[])),
            bytes_hashed: 0
        }
    }

    pub fn bytes_hashed(&self) -> u64 {
        self.bytes_hashed
    }

    pub fn finish(self) -> Fingerprint {
        let mut fingerprint = Fingerprint::zero();
        fingerprint.0.copy_from_slice(self.state.into_inner().finalize());
        fingerprint
    }
}

impl ::std::hash::Hasher for IchHasher {
    fn finish(&self) -> u64 {
        bug!("Use other finish() implementation to get the full 128-bit hash.");
    }

    #[inline]
    fn write(&mut self, bytes: &[u8]) {
        self.state.write(bytes);
        self.bytes_hashed += bytes.len() as u64;
    }
}
<commit_msg>leb128-encode integers before hashing them in IchHasher.<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::mem;
use std::hash::Hasher;
use rustc_data_structures::blake2b::Blake2bHasher;
use rustc::ty::util::ArchIndependentHasher;
use ich::Fingerprint;
use rustc_serialize::leb128::write_unsigned_leb128;

#[derive(Debug)]
pub struct IchHasher {
    state: ArchIndependentHasher<Blake2bHasher>,
    leb128_helper: Vec<u8>,
    bytes_hashed: u64,
}

impl IchHasher {
    pub fn new() -> IchHasher {
        let hash_size = mem::size_of::<Fingerprint>();
        IchHasher {
            state: ArchIndependentHasher::new(Blake2bHasher::new(hash_size, &[])),
            leb128_helper: vec![],
            bytes_hashed: 0
        }
    }

    pub fn bytes_hashed(&self) -> u64 {
        self.bytes_hashed
    }

    pub fn finish(self) -> Fingerprint {
        let mut fingerprint = Fingerprint::zero();
        fingerprint.0.copy_from_slice(self.state.into_inner().finalize());
        fingerprint
    }

    #[inline]
    fn write_uleb128(&mut self, value: u64) {
        let len = write_unsigned_leb128(&mut self.leb128_helper, 0, value);
        self.state.write(&self.leb128_helper[0..len]);
        self.bytes_hashed += len as u64;
    }
}

// For the non-u8 integer cases we leb128 encode them first. Because small
// integers dominate, this significantly and cheaply reduces the number of
// bytes hashed, which is good because blake2b is expensive.
impl Hasher for IchHasher {
    fn finish(&self) -> u64 {
        bug!("Use other finish() implementation to get the full 128-bit hash.");
    }

    #[inline]
    fn write(&mut self, bytes: &[u8]) {
        self.state.write(bytes);
        self.bytes_hashed += bytes.len() as u64;
    }

    // There is no need to leb128-encode u8 values.

    #[inline]
    fn write_u16(&mut self, i: u16) {
        self.write_uleb128(i as u64);
    }

    #[inline]
    fn write_u32(&mut self, i: u32) {
        self.write_uleb128(i as u64);
    }

    #[inline]
    fn write_u64(&mut self, i: u64) {
        self.write_uleb128(i);
    }

    #[inline]
    fn write_usize(&mut self, i: usize) {
        self.write_uleb128(i as u64);
    }
}
<|endoftext|>


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

use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding;
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElementMethods;
use dom::bindings::codegen::InheritTypes::HTMLCanvasElementDerived;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast};
use dom::bindings::global::Window;
use dom::bindings::js::{MutNullableJS, JSRef, Temporary, OptionalSettable};
use dom::bindings::trace::Traceable;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::canvasrenderingcontext2d::CanvasRenderingContext2D;
use dom::document::Document;
use dom::element::{Element, HTMLCanvasElementTypeId, AttributeHandlers};
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;

use servo_util::str::{DOMString, parse_unsigned_integer};
use string_cache::Atom;

use geom::size::Size2D;

use std::cell::Cell;
use std::default::Default;

static DefaultWidth: u32 = 300;
static DefaultHeight: u32 = 150;

#[jstraceable]
#[must_root]
pub struct HTMLCanvasElement {
    pub htmlelement: HTMLElement,
    context: Traceable<MutNullableJS<CanvasRenderingContext2D>>,
    width: Traceable<Cell<u32>>,
    height: Traceable<Cell<u32>>,
}

impl HTMLCanvasElementDerived for EventTarget {
    fn is_htmlcanvaselement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLCanvasElementTypeId))
    }
}

impl HTMLCanvasElement {
    fn new_inherited(localName: DOMString, document: JSRef<Document>) -> HTMLCanvasElement {
        HTMLCanvasElement {
            htmlelement: HTMLElement::new_inherited(HTMLCanvasElementTypeId, localName, document),
            context: Traceable::new(Default::default()),
            width: Traceable::new(Cell::new(DefaultWidth)),
            height: Traceable::new(Cell::new(DefaultHeight)),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, document: JSRef<Document>) -> Temporary<HTMLCanvasElement> {
        let element = HTMLCanvasElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLCanvasElementBinding::Wrap)
    }
}

impl<'a> HTMLCanvasElementMethods for JSRef<'a, HTMLCanvasElement> {
    fn Width(self) -> u32 {
        self.width.get()
    }

    fn SetWidth(self, width: u32) {
        let elem: JSRef<Element> = ElementCast::from_ref(self);
        elem.set_uint_attribute("width", width)
    }

    fn Height(self) -> u32 {
        self.height.get()
    }

    fn SetHeight(self, height: u32) {
        let elem: JSRef<Element> = ElementCast::from_ref(self);
        elem.set_uint_attribute("height", height)
    }

    fn GetContext(self, id: DOMString) -> Option<Temporary<CanvasRenderingContext2D>> {
        if id.as_slice() != "2d" {
            return None;
        }

        if self.context.get().is_none() {
            let window = window_from_node(self).root();
            let (w, h) = (self.width.get() as i32, self.height.get() as i32);
            let context = CanvasRenderingContext2D::new(&Window(*window), self, Size2D(w, h));
            self.context.assign(Some(context));
        }
        self.context.get()
     }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLCanvasElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
        let element: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
        Some(element as &VirtualMethods)
    }

    fn before_remove_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(name, value.clone()),
            _ => (),
        }

        let recreate = match name.as_slice() {
            "width" => {
                self.width.set(DefaultWidth);
                true
            }
            "height" => {
                self.height.set(DefaultHeight);
                true
            }
            _ => false,
        };

        if recreate {
            let (w, h) = (self.width.get() as i32, self.height.get() as i32);
            match self.context.get() {
                Some(ref context) => context.root().recreate(Size2D(w, h)),
                None => ()
            }
        }
    }

    fn after_set_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(name, value.clone()),
            _ => (),
        }

        let recreate = match name.as_slice() {
            "width" => {
                self.width.set(parse_unsigned_integer(value.as_slice().chars()).unwrap_or(DefaultWidth));
                true
            }
            "height" => {
                self.height.set(parse_unsigned_integer(value.as_slice().chars()).unwrap_or(DefaultHeight));
                true
            }
            _ => false,
        };

        if recreate {
            let (w, h) = (self.width.get() as i32, self.height.get() as i32);
            match self.context.get() {
                Some(ref context) => context.root().recreate(Size2D(w, h)),
                None => ()
            }
        }
    }
}

impl Reflectable for HTMLCanvasElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<commit_msg>Remove Traceable from htmlcanvaselement.rs<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding;
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElementMethods;
use dom::bindings::codegen::InheritTypes::HTMLCanvasElementDerived;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast};
use dom::bindings::global::Window;
use dom::bindings::js::{MutNullableJS, JSRef, Temporary, OptionalSettable};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::canvasrenderingcontext2d::CanvasRenderingContext2D;
use dom::document::Document;
use dom::element::{Element, HTMLCanvasElementTypeId, AttributeHandlers};
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;

use servo_util::str::{DOMString, parse_unsigned_integer};
use string_cache::Atom;

use geom::size::Size2D;

use std::cell::Cell;
use std::default::Default;

static DefaultWidth: u32 = 300;
static DefaultHeight: u32 = 150;

#[jstraceable]
#[must_root]
pub struct HTMLCanvasElement {
    pub htmlelement: HTMLElement,
    context: MutNullableJS<CanvasRenderingContext2D>,
    width: Cell<u32>,
    height: Cell<u32>,
}

impl HTMLCanvasElementDerived for EventTarget {
    fn is_htmlcanvaselement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLCanvasElementTypeId))
    }
}

impl HTMLCanvasElement {
    fn new_inherited(localName: DOMString, document: JSRef<Document>) -> HTMLCanvasElement {
        HTMLCanvasElement {
            htmlelement: HTMLElement::new_inherited(HTMLCanvasElementTypeId, localName, document),
            context: Default::default(),
            width: Cell::new(DefaultWidth),
            height: Cell::new(DefaultHeight),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, document: JSRef<Document>) -> Temporary<HTMLCanvasElement> {
        let element = HTMLCanvasElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLCanvasElementBinding::Wrap)
    }
}

impl<'a> HTMLCanvasElementMethods for JSRef<'a, HTMLCanvasElement> {
    fn Width(self) -> u32 {
        self.width.get()
    }

    fn SetWidth(self, width: u32) {
        let elem: JSRef<Element> = ElementCast::from_ref(self);
        elem.set_uint_attribute("width", width)
    }

    fn Height(self) -> u32 {
        self.height.get()
    }

    fn SetHeight(self, height: u32) {
        let elem: JSRef<Element> = ElementCast::from_ref(self);
        elem.set_uint_attribute("height", height)
    }

    fn GetContext(self, id: DOMString) -> Option<Temporary<CanvasRenderingContext2D>> {
        if id.as_slice() != "2d" {
            return None;
        }

        if self.context.get().is_none() {
            let window = window_from_node(self).root();
            let (w, h) = (self.width.get() as i32, self.height.get() as i32);
            let context = CanvasRenderingContext2D::new(&Window(*window), self, Size2D(w, h));
            self.context.assign(Some(context));
        }
        self.context.get()
     }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLCanvasElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
        let element: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
        Some(element as &VirtualMethods)
    }

    fn before_remove_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(name, value.clone()),
            _ => (),
        }

        let recreate = match name.as_slice() {
            "width" => {
                self.width.set(DefaultWidth);
                true
            }
            "height" => {
                self.height.set(DefaultHeight);
                true
            }
            _ => false,
        };

        if recreate {
            let (w, h) = (self.width.get() as i32, self.height.get() as i32);
            match self.context.get() {
                Some(ref context) => context.root().recreate(Size2D(w, h)),
                None => ()
            }
        }
    }

    fn after_set_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(name, value.clone()),
            _ => (),
        }

        let recreate = match name.as_slice() {
            "width" => {
                self.width.set(parse_unsigned_integer(value.as_slice().chars()).unwrap_or(DefaultWidth));
                true
            }
            "height" => {
                self.height.set(parse_unsigned_integer(value.as_slice().chars()).unwrap_or(DefaultHeight));
                true
            }
            _ => false,
        };

        if recreate {
            let (w, h) = (self.width.get() as i32, self.height.get() as i32);
            match self.context.get() {
                Some(ref context) => context.root().recreate(Size2D(w, h)),
                None => ()
            }
        }
    }
}

impl Reflectable for HTMLCanvasElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<|endoftext|>


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

use dom::attr::AttrHelpers;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLIFrameElementDerived};
use dom::bindings::js::{JSRef, Temporary, OptionalRootable};
use dom::bindings::trace::Traceable;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::document::Document;
use dom::element::{HTMLIFrameElementTypeId, Element};
use dom::element::AttributeHandlers;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::window::Window;
use page::IterablePage;

use servo_msg::constellation_msg::{PipelineId, SubpageId};
use servo_msg::constellation_msg::{IFrameSandboxed, IFrameUnsandboxed};
use servo_msg::constellation_msg::{ConstellationChan, LoadIframeUrlMsg};
use servo_util::atom::Atom;
use servo_util::namespace::Null;
use servo_util::str::DOMString;

use std::ascii::StrAsciiExt;
use std::cell::Cell;
use url::{Url, UrlParser};

enum SandboxAllowance {
    AllowNothing = 0x00,
    AllowSameOrigin = 0x01,
    AllowTopNavigation = 0x02,
    AllowForms = 0x04,
    AllowScripts = 0x08,
    AllowPointerLock = 0x10,
    AllowPopups = 0x20
}

#[deriving(Encodable)]
pub struct HTMLIFrameElement {
    pub htmlelement: HTMLElement,
    pub size: Traceable<Cell<Option<IFrameSize>>>,
    pub sandbox: Traceable<Cell<Option<u8>>>,
}

impl HTMLIFrameElementDerived for EventTarget {
    fn is_htmliframeelement(&self) -> bool {
       self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLIFrameElementTypeId))
    }
}

#[deriving(Encodable)]
pub struct IFrameSize {
    pub pipeline_id: PipelineId,
    pub subpage_id: SubpageId,
}

pub trait HTMLIFrameElementHelpers {
    fn is_sandboxed(&self) -> bool;
    fn get_url(&self) -> Option<Url>;
    /// http://www.whatwg.org/html/#process-the-iframe-attributes
    fn process_the_iframe_attributes(&self);
}

impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> {
    fn is_sandboxed(&self) -> bool {
        self.sandbox.deref().get().is_some()
    }

    fn get_url(&self) -> Option<Url> {
        let element: &JSRef<Element> = ElementCast::from_ref(self);
        element.get_attribute(Null, "src").root().and_then(|src| {
            let window = window_from_node(self).root();
            UrlParser::new().base_url(&window.deref().page().get_url())
                .parse(src.deref().value().as_slice()).ok()
        })
    }

    fn process_the_iframe_attributes(&self) {
        let url = match self.get_url() {
            Some(url) => url.clone(),
            None => Url::parse("about:blank").unwrap(),
        };

        let sandboxed = if self.is_sandboxed() {
            IFrameSandboxed
        } else {
            IFrameUnsandboxed
        };

        // Subpage Id
        let window = window_from_node(self).root();
        let page = window.deref().page();
        let subpage_id = page.get_next_subpage_id();

        self.deref().size.deref().set(Some(IFrameSize {
            pipeline_id: page.id,
            subpage_id: subpage_id,
        }));

        let ConstellationChan(ref chan) = *page.constellation_chan.deref();
        chan.send(LoadIframeUrlMsg(url, page.id, subpage_id, sandboxed));
    }
}

impl HTMLIFrameElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLIFrameElement {
        HTMLIFrameElement {
            htmlelement: HTMLElement::new_inherited(HTMLIFrameElementTypeId, localName, document),
            size: Traceable::new(Cell::new(None)),
            sandbox: Traceable::new(Cell::new(None)),
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLIFrameElement> {
        let element = HTMLIFrameElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLIFrameElementBinding::Wrap)
    }
}

impl<'a> HTMLIFrameElementMethods for JSRef<'a, HTMLIFrameElement> {
    fn Src(&self) -> DOMString {
        let element: &JSRef<Element> = ElementCast::from_ref(self);
        element.get_string_attribute("src")
    }

    fn SetSrc(&self, src: DOMString) {
        let element: &JSRef<Element> = ElementCast::from_ref(self);
        element.set_url_attribute("src", src)
    }

    fn Sandbox(&self) -> DOMString {
        let element: &JSRef<Element> = ElementCast::from_ref(self);
        element.get_string_attribute("sandbox")
    }

    fn SetSandbox(&self, sandbox: DOMString) {
        let element: &JSRef<Element> = ElementCast::from_ref(self);
        element.set_string_attribute("sandbox", sandbox);
    }

    fn GetContentWindow(&self) -> Option<Temporary<Window>> {
        self.size.deref().get().and_then(|size| {
            let window = window_from_node(self).root();
            let children = &*window.deref().page.children.deref().borrow();
            let child = children.iter().find(|child| {
                child.subpage_id.unwrap() == size.subpage_id
            });
            child.and_then(|page| {
                page.frame.deref().borrow().as_ref().map(|frame| {
                    Temporary::new(frame.window.clone())
                })
            })
        })
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLIFrameElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn after_set_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(name, value.clone()),
            _ => (),
        }

        if "sandbox" == name.as_slice() {
            let mut modes = AllowNothing as u8;
            for word in value.as_slice().split(' ') {
                modes |= match word.to_ascii_lower().as_slice() {
                    "allow-same-origin" => AllowSameOrigin,
                    "allow-forms" => AllowForms,
                    "allow-pointer-lock" => AllowPointerLock,
                    "allow-popups" => AllowPopups,
                    "allow-scripts" => AllowScripts,
                    "allow-top-navigation" => AllowTopNavigation,
                    _ => AllowNothing
                } as u8;
            }
            self.deref().sandbox.deref().set(Some(modes));
        }

        if "src" == name.as_slice() {
            let node: &JSRef<Node> = NodeCast::from_ref(self);
            if node.is_in_doc() {
                self.process_the_iframe_attributes()
            }
        }
    }

    fn before_remove_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(name, value),
            _ => (),
        }

        if "sandbox" == name.as_slice() {
            self.deref().sandbox.deref().set(None);
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => (),
        }

        if tree_in_doc {
            self.process_the_iframe_attributes();
        }
    }
}

impl Reflectable for HTMLIFrameElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<commit_msg>Handle src='' in an iframe element. Without this, infinitely creates iframes with the same url.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::attr::AttrHelpers;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLIFrameElementDerived};
use dom::bindings::js::{JSRef, Temporary, OptionalRootable};
use dom::bindings::trace::Traceable;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::document::Document;
use dom::element::{HTMLIFrameElementTypeId, Element};
use dom::element::AttributeHandlers;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::window::Window;
use page::IterablePage;

use servo_msg::constellation_msg::{PipelineId, SubpageId};
use servo_msg::constellation_msg::{IFrameSandboxed, IFrameUnsandboxed};
use servo_msg::constellation_msg::{ConstellationChan, LoadIframeUrlMsg};
use servo_util::atom::Atom;
use servo_util::namespace::Null;
use servo_util::str::DOMString;

use std::ascii::StrAsciiExt;
use std::cell::Cell;
use url::{Url, UrlParser};

enum SandboxAllowance {
    AllowNothing = 0x00,
    AllowSameOrigin = 0x01,
    AllowTopNavigation = 0x02,
    AllowForms = 0x04,
    AllowScripts = 0x08,
    AllowPointerLock = 0x10,
    AllowPopups = 0x20
}

#[deriving(Encodable)]
pub struct HTMLIFrameElement {
    pub htmlelement: HTMLElement,
    pub size: Traceable<Cell<Option<IFrameSize>>>,
    pub sandbox: Traceable<Cell<Option<u8>>>,
}

impl HTMLIFrameElementDerived for EventTarget {
    fn is_htmliframeelement(&self) -> bool {
       self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLIFrameElementTypeId))
    }
}

#[deriving(Encodable)]
pub struct IFrameSize {
    pub pipeline_id: PipelineId,
    pub subpage_id: SubpageId,
}

pub trait HTMLIFrameElementHelpers {
    fn is_sandboxed(&self) -> bool;
    fn get_url(&self) -> Option<Url>;
    /// http://www.whatwg.org/html/#process-the-iframe-attributes
    fn process_the_iframe_attributes(&self);
}

impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> {
    fn is_sandboxed(&self) -> bool {
        self.sandbox.deref().get().is_some()
    }

    fn get_url(&self) -> Option<Url> {
        let element: &JSRef<Element> = ElementCast::from_ref(self);
        element.get_attribute(Null, "src").root().and_then(|src| {
            let url = src.deref().value();
            if url.as_slice().is_empty() {
                None
            } else {
                let window = window_from_node(self).root();
                UrlParser::new().base_url(&window.deref().page().get_url())
                    .parse(url.as_slice()).ok()
            }
        })
    }

    fn process_the_iframe_attributes(&self) {
        let url = match self.get_url() {
            Some(url) => url.clone(),
            None => Url::parse("about:blank").unwrap(),
        };

        let sandboxed = if self.is_sandboxed() {
            IFrameSandboxed
        } else {
            IFrameUnsandboxed
        };

        // Subpage Id
        let window = window_from_node(self).root();
        let page = window.deref().page();
        let subpage_id = page.get_next_subpage_id();

        self.deref().size.deref().set(Some(IFrameSize {
            pipeline_id: page.id,
            subpage_id: subpage_id,
        }));

        let ConstellationChan(ref chan) = *page.constellation_chan.deref();
        chan.send(LoadIframeUrlMsg(url, page.id, subpage_id, sandboxed));
    }
}

impl HTMLIFrameElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLIFrameElement {
        HTMLIFrameElement {
            htmlelement: HTMLElement::new_inherited(HTMLIFrameElementTypeId, localName, document),
            size: Traceable::new(Cell::new(None)),
            sandbox: Traceable::new(Cell::new(None)),
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLIFrameElement> {
        let element = HTMLIFrameElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLIFrameElementBinding::Wrap)
    }
}

impl<'a> HTMLIFrameElementMethods for JSRef<'a, HTMLIFrameElement> {
    fn Src(&self) -> DOMString {
        let element: &JSRef<Element> = ElementCast::from_ref(self);
        element.get_string_attribute("src")
    }

    fn SetSrc(&self, src: DOMString) {
        let element: &JSRef<Element> = ElementCast::from_ref(self);
        element.set_url_attribute("src", src)
    }

    fn Sandbox(&self) -> DOMString {
        let element: &JSRef<Element> = ElementCast::from_ref(self);
        element.get_string_attribute("sandbox")
    }

    fn SetSandbox(&self, sandbox: DOMString) {
        let element: &JSRef<Element> = ElementCast::from_ref(self);
        element.set_string_attribute("sandbox", sandbox);
    }

    fn GetContentWindow(&self) -> Option<Temporary<Window>> {
        self.size.deref().get().and_then(|size| {
            let window = window_from_node(self).root();
            let children = &*window.deref().page.children.deref().borrow();
            let child = children.iter().find(|child| {
                child.subpage_id.unwrap() == size.subpage_id
            });
            child.and_then(|page| {
                page.frame.deref().borrow().as_ref().map(|frame| {
                    Temporary::new(frame.window.clone())
                })
            })
        })
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLIFrameElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn after_set_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(name, value.clone()),
            _ => (),
        }

        if "sandbox" == name.as_slice() {
            let mut modes = AllowNothing as u8;
            for word in value.as_slice().split(' ') {
                modes |= match word.to_ascii_lower().as_slice() {
                    "allow-same-origin" => AllowSameOrigin,
                    "allow-forms" => AllowForms,
                    "allow-pointer-lock" => AllowPointerLock,
                    "allow-popups" => AllowPopups,
                    "allow-scripts" => AllowScripts,
                    "allow-top-navigation" => AllowTopNavigation,
                    _ => AllowNothing
                } as u8;
            }
            self.deref().sandbox.deref().set(Some(modes));
        }

        if "src" == name.as_slice() {
            let node: &JSRef<Node> = NodeCast::from_ref(self);
            if node.is_in_doc() {
                self.process_the_iframe_attributes()
            }
        }
    }

    fn before_remove_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(name, value),
            _ => (),
        }

        if "sandbox" == name.as_slice() {
            self.deref().sandbox.deref().set(None);
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => (),
        }

        if tree_in_doc {
            self.process_the_iframe_attributes();
        }
    }
}

impl Reflectable for HTMLIFrameElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[link(name = "issue_2526",
       vers = "0.2",
       uuid = "54cc1bc9-02b8-447c-a227-75ebc923bc29")];
#[crate_type = "lib"];

extern mod std;

export context;

struct arc_destruct<T:Const> {
  _data: int,
}

impl<T:Const> arc_destruct<T> : Drop {
    fn finalize(&self) {}
}

fn arc_destruct<T: Const>(data: int) -> arc_destruct<T> {
    arc_destruct {
        _data: data
    }
}

fn arc<T: Const>(_data: T) -> arc_destruct<T> {
    arc_destruct(0)
}

fn init() -> arc_destruct<context_res> unsafe {
    arc(context_res())
}

struct context_res {
    ctx : int,
}

impl context_res : Drop {
    fn finalize(&self) {}
}

fn context_res() -> context_res {
    context_res {
        ctx: 0
    }
}

type context = arc_destruct<context_res>;

impl context {
    fn socket() { }
}
<commit_msg>test: fix issue 2526 'unsafe' block-keyword, r=burningtree.<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[link(name = "issue_2526",
       vers = "0.2",
       uuid = "54cc1bc9-02b8-447c-a227-75ebc923bc29")];
#[crate_type = "lib"];

extern mod std;

export context;

struct arc_destruct<T:Const> {
  _data: int,
}

impl<T:Const> arc_destruct<T> : Drop {
    fn finalize(&self) {}
}

fn arc_destruct<T: Const>(data: int) -> arc_destruct<T> {
    arc_destruct {
        _data: data
    }
}

fn arc<T: Const>(_data: T) -> arc_destruct<T> {
    arc_destruct(0)
}

fn init() -> arc_destruct<context_res> {
    unsafe {
        arc(context_res())
    }
}

struct context_res {
    ctx : int,
}

impl context_res : Drop {
    fn finalize(&self) {}
}

fn context_res() -> context_res {
    context_res {
        ctx: 0
    }
}

type context = arc_destruct<context_res>;

impl context {
    fn socket() { }
}
<|endoftext|>


<commit_before><commit_msg>Add regression test for #18661<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that param substitutions from the correct environment are
// used when translating unboxed closure calls.

#![feature(unboxed_closures)]

pub fn inside<F: Fn()>(c: F) {
    c.call(());
}

// Use different number of type parameters and closure type to trigger
// an obvious ICE when param environments are mixed up
pub fn outside<A,B>() {
    inside(|&:| {});
}

fn main() {
    outside::<(),()>();
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

struct Foo<T>(T, T);

impl<T> Foo<T> {
    fn foo(&self) {
        match *self {
            Foo::<T>(ref x, ref y) => {
              println!("Goodbye, World!")
            }
        }
    }
}

fn main() {
  match 42 {
    x if x < 7 => (),
    _ => ()
  }
}
<commit_msg>Remove questionable pattern<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
  match 42 {
    x if x < 7 => (),
    _ => ()
  }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Utility macros for implementing PartialEq on slice-like types

#![doc(hidden)]

#[macro_export]
macro_rules! __impl_slice_eq1 {
    ($Lhs: ty, $Rhs: ty) => {
        __impl_slice_eq1! { $Lhs, $Rhs, Sized }
    };
    ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
            #[inline]
            fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] }
            #[inline]
            fn ne(&self, other: &$Rhs) -> bool { &self[..] != &other[..] }
        }
    }
}

#[macro_export]
macro_rules! __impl_slice_eq2 {
    ($Lhs: ty, $Rhs: ty) => {
        __impl_slice_eq2! { $Lhs, $Rhs, Sized }
    };
    ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
        __impl_slice_eq1!($Lhs, $Rhs, $Bound);

        #[stable(feature = "rust1", since = "1.0.0")]
        impl<'a, 'b, A: $Bound, B> PartialEq<$Lhs> for $Rhs where B: PartialEq<A> {
            #[inline]
            fn eq(&self, other: &$Lhs) -> bool { &self[..] == &other[..] }
            #[inline]
            fn ne(&self, other: &$Lhs) -> bool { &self[..] != &other[..] }
        }
    }
}
<commit_msg>Remove one level of indirection for slice-based PartialEq impls<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Utility macros for implementing PartialEq on slice-like types

#![doc(hidden)]

#[macro_export]
macro_rules! __impl_slice_eq1 {
    ($Lhs: ty, $Rhs: ty) => {
        __impl_slice_eq1! { $Lhs, $Rhs, Sized }
    };
    ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
            #[inline]
            fn eq(&self, other: &$Rhs) -> bool { self[..] == other[..] }
            #[inline]
            fn ne(&self, other: &$Rhs) -> bool { self[..] != other[..] }
        }
    }
}

#[macro_export]
macro_rules! __impl_slice_eq2 {
    ($Lhs: ty, $Rhs: ty) => {
        __impl_slice_eq2! { $Lhs, $Rhs, Sized }
    };
    ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
        __impl_slice_eq1!($Lhs, $Rhs, $Bound);

        #[stable(feature = "rust1", since = "1.0.0")]
        impl<'a, 'b, A: $Bound, B> PartialEq<$Lhs> for $Rhs where B: PartialEq<A> {
            #[inline]
            fn eq(&self, other: &$Lhs) -> bool { self[..] == other[..] }
            #[inline]
            fn ne(&self, other: &$Lhs) -> bool { self[..] != other[..] }
        }
    }
}
<|endoftext|>