<commit_before>use std::fmt;
use std::str;
use std::char;
use std::convert;

use byteorder::{ByteOrder, BigEndian};
use unicode_names;
use unicode_width::UnicodeWidthChar;

use super::ascii;

pub fn describe(c: char) {
    println!("{}\n", Describable::from(c));
}

struct Describable {
    c: char,
}

impl fmt::Display for Describable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let cp : Codepoint = self.c.into();
        try!(cp.fmt(f));
        let printable : Printable = self.c.into();
        try!(write!(f, "\n{}", printable));
        let unicode_name = unicode_names::name(self.c);
        if let Some(n) = unicode_name.clone() {
            try!(write!(f, "\nUnicode name: {}", n));
        }
        if let Some(ascii) = ascii::additional_names(self.c) {
            let mut synonyms: Vec<&str> = vec!();
            let mut xmls: Option<&str> = None;
            let mnemos: Vec<&str> = ascii.mnemonics.iter().filter(|n| n.len() != 1).map(|s| *s).collect();
            for syn in ascii.synonyms {
                if syn.starts_with('&') && syn.ends_with(';') {
                    xmls = Some(syn);
                } else if let Some(unicode) = unicode_name.clone() {
                    if format!("{}", unicode).as_str().to_lowercase() != *syn.to_lowercase() {
                        synonyms.push(syn);
                    }
                } else {
                    synonyms.push(syn);
                }
            }
            if !mnemos.is_empty() {
                try!(write!(f, "\nCalled: {}", mnemos.join(", ")));
            }
            if !synonyms.is_empty() {
                try!(write!(f, "\nAlso known as: {}", synonyms.join(", ")));
            }
            if let Some(xml) = xmls {
                try!(write!(f, "\nEscapes in XML as: {}", xml));
            }
            if let Some(n) = ascii.note {
                try!(write!(f, "\nNote: {}", n));
            }
        }
        Ok(())
    }
}

impl convert::From<char> for Describable {
    fn from(c: char) -> Describable {
        Describable{c: c}
    }
}

struct Printable {
    c: char,
}

impl convert::From<char> for Printable {
    fn from(c: char) -> Printable {
        Printable{c: c}
    }
}

fn control_char(ch: char) -> char {
    match ch as u8 {
        0x7f => '?',
        _ => (b'@' + (ch as u8 & 0x1f)) as char
    }
}

impl fmt::Display for Printable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let quote : String = self.c.escape_default().collect();
        if self.c.is_control() {
            try!(write!(f, "Control character; quotes as {}, called ^{}", quote, control_char(self.c)));
        } else {
            if let (Some(width), Some(cjk_width)) = (self.c.width(), self.c.width_cjk()) {
                if width == cjk_width {
                    try!(write!(f, "Width: {}, ", width));
                } else {
                    try!(write!(f, "Width: {} ({} in CJK context), ", width, cjk_width));
                }
            }
            if ! self.c.is_whitespace() {
                try!(write!(f, "prints as {}", self.c));
            } else {
                try!(write!(f, "prints as `{}'", self.c));
            }

            // Check if we can up/downcase:
            let mut caseflipped = String::new();
            if self.c.is_uppercase() {
                for c in self.c.to_lowercase() {
                    caseflipped.push(c);
                }
                try!(write!(f, "\nUpper case. Downcases to {}", caseflipped));
            } else if self.c.is_lowercase() {
                for c in self.c.to_uppercase() {
                    caseflipped.push(c);
                }
                try!(write!(f, "\nLower case. Upcases to {}", caseflipped));
            }

            // If we have quotable text, print that too:
            if quote.len() > 1 {
                try!(write!(f, "\nQuotes as {}", quote));
            }
        }
        Ok(())
    }
}

enum Codepoint {
    ASCII7bit(char),
    Latin1(char),
    UnicodeBasic(char),
    UnicodeWide(char)
}

impl convert::From<char> for Codepoint {
    fn from(c: char) -> Codepoint {
        match c as u32 {
            0 ... 128 => Codepoint::ASCII7bit(c),
            128 ... 256 => Codepoint::Latin1(c),
            256 ... 65536 => Codepoint::UnicodeBasic(c),
            _ => Codepoint::UnicodeWide(c),
        }
    }
}

impl fmt::Display for Codepoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Codepoint::ASCII7bit(c) => {
                let num = c as u32;
                write!(f, "ASCII {:1x}/{:1x}, {:3}, 0x{:02x}, 0{:03o}, bits {:08b}",
                       (num & 0xf0) >> 4, num & 0x0f, num, num, num, num)
            }
            Codepoint::Latin1(c) => {
                let num = c as u32;
                write!(f, "LATIN1 {:02x}, {:3}, 0x{:02x}, 0{:03o}, bits {:08b}",
                       num, num, num, num, num)
            }
            Codepoint::UnicodeBasic(c) | Codepoint::UnicodeWide(c) => {
                let num = c as u32;
                let mut string = String::new();
                string.push(c);
                let s = string.as_str();
                let utf8 = ByteRepresentation::from(s.bytes());
                let utf16 = ByteRepresentation::from(s.encode_utf16());
                let width = match *self {
                    Codepoint::UnicodeWide(_) => 8,
                    _ => 4,
                };
                write!(f, "U+{:0width$X}, &#{:}; 0x{:0width$X}, \\0{:o}, UTF-8: {}, UTF-16BE: {}",
                       num, num, num, num, utf8, utf16, width = width)
            }
        }
    }
}

enum ByteRepresentation {
    UTF8(Vec<u8>),
    UTF16BE(Vec<u8>),
}

impl<'a> convert::From<str::EncodeUtf16<'a>> for ByteRepresentation {
    fn from(bs: str::EncodeUtf16<'a>) -> ByteRepresentation {
        let words: Vec<u16> = bs.collect();
        let mut buf: Vec<u8> = Vec::with_capacity(words.len() * 2);
        for word in words {
            let mut split_word = [0; 2];
            BigEndian::write_u16(&mut split_word, word);
            buf.extend_from_slice(&split_word);
        }

        ByteRepresentation::UTF16BE(buf)
    }
}

impl<'a> convert::From<str::Bytes<'a>> for ByteRepresentation {
    fn from(bs: str::Bytes<'a>) -> ByteRepresentation {
        let bytes: Vec<u8> = bs.collect();
        ByteRepresentation::UTF8(bytes)
    }
}

impl fmt::Display for ByteRepresentation {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            ByteRepresentation::UTF8(ref bytes) => {
                let mut byte_iter = bytes.iter();
                try!(write!(f, "{:02x}", byte_iter.next().unwrap()));
                for byte in byte_iter {
                    try!(write!(f, " {:02x}", byte));
                }
            },
            ByteRepresentation::UTF16BE(ref bytes) => {
                for byte in bytes.iter() {
                    try!(write!(f, "{:02x}", byte));
                }
            }
        }
        Ok(())
    }
}
<commit_msg>Errr, fix ASCII7bit&latin1&basic unicode bounds<commit_after>use std::fmt;
use std::str;
use std::char;
use std::convert;

use byteorder::{ByteOrder, BigEndian};
use unicode_names;
use unicode_width::UnicodeWidthChar;

use super::ascii;

pub fn describe(c: char) {
    println!("{}\n", Describable::from(c));
}

struct Describable {
    c: char,
}

impl fmt::Display for Describable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let cp : Codepoint = self.c.into();
        try!(cp.fmt(f));
        let printable : Printable = self.c.into();
        try!(write!(f, "\n{}", printable));
        let unicode_name = unicode_names::name(self.c);
        if let Some(n) = unicode_name.clone() {
            try!(write!(f, "\nUnicode name: {}", n));
        }
        if let Some(ascii) = ascii::additional_names(self.c) {
            let mut synonyms: Vec<&str> = vec!();
            let mut xmls: Option<&str> = None;
            let mnemos: Vec<&str> = ascii.mnemonics.iter().filter(|n| n.len() != 1).map(|s| *s).collect();
            for syn in ascii.synonyms {
                if syn.starts_with('&') && syn.ends_with(';') {
                    xmls = Some(syn);
                } else if let Some(unicode) = unicode_name.clone() {
                    if format!("{}", unicode).as_str().to_lowercase() != *syn.to_lowercase() {
                        synonyms.push(syn);
                    }
                } else {
                    synonyms.push(syn);
                }
            }
            if !mnemos.is_empty() {
                try!(write!(f, "\nCalled: {}", mnemos.join(", ")));
            }
            if !synonyms.is_empty() {
                try!(write!(f, "\nAlso known as: {}", synonyms.join(", ")));
            }
            if let Some(xml) = xmls {
                try!(write!(f, "\nEscapes in XML as: {}", xml));
            }
            if let Some(n) = ascii.note {
                try!(write!(f, "\nNote: {}", n));
            }
        }
        Ok(())
    }
}

impl convert::From<char> for Describable {
    fn from(c: char) -> Describable {
        Describable{c: c}
    }
}

struct Printable {
    c: char,
}

impl convert::From<char> for Printable {
    fn from(c: char) -> Printable {
        Printable{c: c}
    }
}

fn control_char(ch: char) -> char {
    match ch as u8 {
        0x7f => '?',
        _ => (b'@' + (ch as u8 & 0x1f)) as char
    }
}

impl fmt::Display for Printable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let quote : String = self.c.escape_default().collect();
        if self.c.is_control() {
            try!(write!(f, "Control character; quotes as {}, called ^{}", quote, control_char(self.c)));
        } else {
            if let (Some(width), Some(cjk_width)) = (self.c.width(), self.c.width_cjk()) {
                if width == cjk_width {
                    try!(write!(f, "Width: {}, ", width));
                } else {
                    try!(write!(f, "Width: {} ({} in CJK context), ", width, cjk_width));
                }
            }
            if ! self.c.is_whitespace() {
                try!(write!(f, "prints as {}", self.c));
            } else {
                try!(write!(f, "prints as `{}'", self.c));
            }

            // Check if we can up/downcase:
            let mut caseflipped = String::new();
            if self.c.is_uppercase() {
                for c in self.c.to_lowercase() {
                    caseflipped.push(c);
                }
                try!(write!(f, "\nUpper case. Downcases to {}", caseflipped));
            } else if self.c.is_lowercase() {
                for c in self.c.to_uppercase() {
                    caseflipped.push(c);
                }
                try!(write!(f, "\nLower case. Upcases to {}", caseflipped));
            }

            // If we have quotable text, print that too:
            if quote.len() > 1 {
                try!(write!(f, "\nQuotes as {}", quote));
            }
        }
        Ok(())
    }
}

enum Codepoint {
    ASCII7bit(char),
    Latin1(char),
    UnicodeBasic(char),
    UnicodeWide(char)
}

impl convert::From<char> for Codepoint {
    fn from(c: char) -> Codepoint {
        match c as u32 {
            0 ... 127 => Codepoint::ASCII7bit(c),
            128 ... 255 => Codepoint::Latin1(c),
            256 ... 65535 => Codepoint::UnicodeBasic(c),
            _ => Codepoint::UnicodeWide(c),
        }
    }
}

impl fmt::Display for Codepoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Codepoint::ASCII7bit(c) => {
                let num = c as u32;
                write!(f, "ASCII {:1x}/{:1x}, {:3}, 0x{:02x}, 0{:03o}, bits {:08b}",
                       (num & 0xf0) >> 4, num & 0x0f, num, num, num, num)
            }
            Codepoint::Latin1(c) => {
                let num = c as u32;
                write!(f, "LATIN1 {:02x}, {:3}, 0x{:02x}, 0{:03o}, bits {:08b}",
                       num, num, num, num, num)
            }
            Codepoint::UnicodeBasic(c) | Codepoint::UnicodeWide(c) => {
                let num = c as u32;
                let mut string = String::new();
                string.push(c);
                let s = string.as_str();
                let utf8 = ByteRepresentation::from(s.bytes());
                let utf16 = ByteRepresentation::from(s.encode_utf16());
                let width = match *self {
                    Codepoint::UnicodeWide(_) => 8,
                    _ => 4,
                };
                write!(f, "U+{:0width$X}, &#{:}; 0x{:0width$X}, \\0{:o}, UTF-8: {}, UTF-16BE: {}",
                       num, num, num, num, utf8, utf16, width = width)
            }
        }
    }
}

enum ByteRepresentation {
    UTF8(Vec<u8>),
    UTF16BE(Vec<u8>),
}

impl<'a> convert::From<str::EncodeUtf16<'a>> for ByteRepresentation {
    fn from(bs: str::EncodeUtf16<'a>) -> ByteRepresentation {
        let words: Vec<u16> = bs.collect();
        let mut buf: Vec<u8> = Vec::with_capacity(words.len() * 2);
        for word in words {
            let mut split_word = [0; 2];
            BigEndian::write_u16(&mut split_word, word);
            buf.extend_from_slice(&split_word);
        }

        ByteRepresentation::UTF16BE(buf)
    }
}

impl<'a> convert::From<str::Bytes<'a>> for ByteRepresentation {
    fn from(bs: str::Bytes<'a>) -> ByteRepresentation {
        let bytes: Vec<u8> = bs.collect();
        ByteRepresentation::UTF8(bytes)
    }
}

impl fmt::Display for ByteRepresentation {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            ByteRepresentation::UTF8(ref bytes) => {
                let mut byte_iter = bytes.iter();
                try!(write!(f, "{:02x}", byte_iter.next().unwrap()));
                for byte in byte_iter {
                    try!(write!(f, " {:02x}", byte));
                }
            },
            ByteRepresentation::UTF16BE(ref bytes) => {
                for byte in bytes.iter() {
                    try!(write!(f, "{:02x}", byte));
                }
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The tiny-http Contributors
// Copyright 2015 The rust-chunked-transfer Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Result as IoResult;
use std::io::Write;

/// Splits the incoming data into HTTP chunks.
///
/// # Example
///
/// ```
/// use chunked_transfer::Encoder;
/// use std::io::Write;
///
/// let mut decoded = "hello world";
/// let mut encoded: Vec<u8> = vec![];
///
/// {
///     let mut encoder = Encoder::with_chunks_size(&mut encoded, 5);
///     encoder.write_all(decoded.as_bytes());
/// }
///
/// assert_eq!(encoded, b"5\r\nhello\r\n5\r\n worl\r\n1\r\nd\r\n0\r\n\r\n");
/// ```
pub struct Encoder<W>
where
    W: Write,
{
    // where to send the result
    output: W,

    // size of each chunk
    chunks_size: usize,

    // data waiting to be sent is stored here
    buffer: Vec<u8>,

    // Flushes the internal buffer after each write. This might be useful
    // if data should be sent immediately to downstream consumers
    flush_after_write: bool
}

impl<W> Encoder<W>
where
    W: Write,
{
    pub fn new(output: W) -> Encoder<W> {
        Encoder::with_chunks_size(output, 8192)
    }

    pub fn with_chunks_size(output: W, chunks: usize) -> Encoder<W> {
        Encoder {
            output,
            chunks_size: chunks,
            buffer: Vec::with_capacity(0),
            flush_after_write: false
        }
    }

    pub fn with_flush_after_write(output: W) -> Encoder<W> {
        Encoder {
            output,
            chunks_size: 8192,
            buffer: Vec::with_capacity(0),
            flush_after_write: true
        }

    }
}

fn send<W>(output: &mut W, data: &[u8]) -> IoResult<()>
where
    W: Write,
{
    write!(output, "{:x}\r\n", data.len())?;
    output.write_all(data)?;
    write!(output, "\r\n")?;
    Ok(())
}

impl<W> Write for Encoder<W>
where
    W: Write,
{
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        self.buffer.write_all(buf)?;

        while self.buffer.len() >= self.chunks_size {
            let rest = {
                let (to_send, rest) = self.buffer.split_at_mut(self.chunks_size);
                send(&mut self.output, to_send)?;
                rest.to_vec()
            };
            self.buffer = rest;
        }
        if self.flush_after_write {
            self.flush()?;
        }

        Ok(buf.len())
    }

    fn flush(&mut self) -> IoResult<()> {
        if self.buffer.is_empty() {
            return Ok(());
        }

        send(&mut self.output, &self.buffer)?;
        self.buffer.clear();
        Ok(())
    }
}

impl<W> Drop for Encoder<W>
where
    W: Write,
{
    fn drop(&mut self) {
        self.flush().ok();
        send(&mut self.output, &[]).ok();
    }
}

#[cfg(test)]
mod test {
    use super::Encoder;
    use std::io;
    use std::io::Write;
    use std::str::from_utf8;

    #[test]
    fn test() {
        let mut source = io::Cursor::new("hello world".to_string().into_bytes());
        let mut dest: Vec<u8> = vec![];

        {
            let mut encoder = Encoder::with_chunks_size(dest.by_ref(), 5);
            io::copy(&mut source, &mut encoder).unwrap();
            assert!(!encoder.buffer.is_empty());
        }

        let output = from_utf8(&dest).unwrap();

        assert_eq!(output, "5\r\nhello\r\n5\r\n worl\r\n1\r\nd\r\n0\r\n\r\n");
    }
     #[test]
    fn flush_after_write() {
        let mut source = io::Cursor::new("hello world".to_string().into_bytes());
        let mut dest: Vec<u8> = vec![];

        {
            let mut encoder = Encoder::with_flush_after_write(dest.by_ref());
            io::copy(&mut source, &mut encoder).unwrap();
            // The internal buffer has been flushed.
            assert!(encoder.buffer.is_empty());
        }

        let output = from_utf8(&dest).unwrap();

        assert_eq!(output, "b\r\nhello world\r\n0\r\n\r\n");
    }
}
<commit_msg>rustfmt<commit_after>// Copyright 2015 The tiny-http Contributors
// Copyright 2015 The rust-chunked-transfer Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Result as IoResult;
use std::io::Write;

/// Splits the incoming data into HTTP chunks.
///
/// # Example
///
/// ```
/// use chunked_transfer::Encoder;
/// use std::io::Write;
///
/// let mut decoded = "hello world";
/// let mut encoded: Vec<u8> = vec![];
///
/// {
///     let mut encoder = Encoder::with_chunks_size(&mut encoded, 5);
///     encoder.write_all(decoded.as_bytes());
/// }
///
/// assert_eq!(encoded, b"5\r\nhello\r\n5\r\n worl\r\n1\r\nd\r\n0\r\n\r\n");
/// ```
pub struct Encoder<W>
where
    W: Write,
{
    // where to send the result
    output: W,

    // size of each chunk
    chunks_size: usize,

    // data waiting to be sent is stored here
    buffer: Vec<u8>,

    // Flushes the internal buffer after each write. This might be useful
    // if data should be sent immediately to downstream consumers
    flush_after_write: bool,
}

impl<W> Encoder<W>
where
    W: Write,
{
    pub fn new(output: W) -> Encoder<W> {
        Encoder::with_chunks_size(output, 8192)
    }

    pub fn with_chunks_size(output: W, chunks: usize) -> Encoder<W> {
        Encoder {
            output,
            chunks_size: chunks,
            buffer: Vec::with_capacity(0),
            flush_after_write: false,
        }
    }

    pub fn with_flush_after_write(output: W) -> Encoder<W> {
        Encoder {
            output,
            chunks_size: 8192,
            buffer: Vec::with_capacity(0),
            flush_after_write: true,
        }
    }
}

fn send<W>(output: &mut W, data: &[u8]) -> IoResult<()>
where
    W: Write,
{
    write!(output, "{:x}\r\n", data.len())?;
    output.write_all(data)?;
    write!(output, "\r\n")?;
    Ok(())
}

impl<W> Write for Encoder<W>
where
    W: Write,
{
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        self.buffer.write_all(buf)?;

        while self.buffer.len() >= self.chunks_size {
            let rest = {
                let (to_send, rest) = self.buffer.split_at_mut(self.chunks_size);
                send(&mut self.output, to_send)?;
                rest.to_vec()
            };
            self.buffer = rest;
        }
        if self.flush_after_write {
            self.flush()?;
        }

        Ok(buf.len())
    }

    fn flush(&mut self) -> IoResult<()> {
        if self.buffer.is_empty() {
            return Ok(());
        }

        send(&mut self.output, &self.buffer)?;
        self.buffer.clear();
        Ok(())
    }
}

impl<W> Drop for Encoder<W>
where
    W: Write,
{
    fn drop(&mut self) {
        self.flush().ok();
        send(&mut self.output, &[]).ok();
    }
}

#[cfg(test)]
mod test {
    use super::Encoder;
    use std::io;
    use std::io::Write;
    use std::str::from_utf8;

    #[test]
    fn test() {
        let mut source = io::Cursor::new("hello world".to_string().into_bytes());
        let mut dest: Vec<u8> = vec![];

        {
            let mut encoder = Encoder::with_chunks_size(dest.by_ref(), 5);
            io::copy(&mut source, &mut encoder).unwrap();
            assert!(!encoder.buffer.is_empty());
        }

        let output = from_utf8(&dest).unwrap();

        assert_eq!(output, "5\r\nhello\r\n5\r\n worl\r\n1\r\nd\r\n0\r\n\r\n");
    }
    #[test]
    fn flush_after_write() {
        let mut source = io::Cursor::new("hello world".to_string().into_bytes());
        let mut dest: Vec<u8> = vec![];

        {
            let mut encoder = Encoder::with_flush_after_write(dest.by_ref());
            io::copy(&mut source, &mut encoder).unwrap();
            // The internal buffer has been flushed.
            assert!(encoder.buffer.is_empty());
        }

        let output = from_utf8(&dest).unwrap();

        assert_eq!(output, "b\r\nhello world\r\n0\r\n\r\n");
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;
use std::io::Error as StdIoError;
use std::iter::repeat;
use rustc_serialize;

use super::{Data, StrVal, Bool, VecVal, Map, OptVal};
pub use self::Error::*;

pub struct Encoder {
    pub data: Vec<Data>,
}

impl Encoder {
    pub fn new() -> Encoder {
        Encoder { data: Vec::new() }
    }
}

pub enum Error {
    NestedOptions,
    UnsupportedType,
    InvalidStr,
    MissingElements,
    KeyIsNotString,
    NoFilename,
    IoError(StdIoError),
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            NestedOptions => "nested Option types are not supported".fmt(f),
            UnsupportedType => "unsupported type".fmt(f),
            InvalidStr => "invalid str".fmt(f),
            MissingElements => "no elements in value".fmt(f),
            KeyIsNotString => "key is not a string".fmt(f),
            NoFilename => "a filename must be provided".fmt(f),
            IoError(ref err) => err.fmt(f),
        }
    }
}

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

pub type EncoderResult = Result<(), Error>;

impl rustc_serialize::Encoder for Encoder {
    type Error = Error;

    fn emit_nil(&mut self) -> EncoderResult { Err(UnsupportedType) }

    fn emit_isize(&mut self, v: isize) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_usize(&mut self, v: usize) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u64(&mut self, v: u64) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u32(&mut self, v: u32) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u16(&mut self, v: u16) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u8(&mut self, v: u8) -> EncoderResult     { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_i64(&mut self, v: i64) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_i32(&mut self, v: i32) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_i16(&mut self, v: i16) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_i8(&mut self, v: i8) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_bool(&mut self, v: bool) -> EncoderResult { self.data.push(Bool(v)); Ok(()) }

    fn emit_f64(&mut self, v: f64) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_f32(&mut self, v: f32) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_char(&mut self, v: char) -> EncoderResult {
        self.data.push(StrVal(repeat(v).take(1).collect::<String>()));
        Ok(())
    }
    fn emit_str(&mut self, v: &str) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_enum< F >(&mut self, _name: &str, _f: F ) -> EncoderResult
    where F : FnOnce(&mut Encoder) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_variant< F >(&mut self,
                         _name: &str,
                         _id: usize,
                         _len: usize,
                         _f: F) -> EncoderResult
                         where F : FnOnce(&mut Encoder) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_variant_arg< F >(&mut self,
                             _a_idx: usize,
                             _f: F) -> EncoderResult
                             where F : FnOnce(&mut Encoder) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_struct_variant< F >(&mut self,
                                _v_name: &str,
                                _v_id: usize,
                                _len: usize,
                                _f: F) -> EncoderResult
                                where F : FnOnce(&mut Encoder) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_struct_variant_field< F >(&mut self,
                                      _f_name: &str,
                                      _f_idx: usize,
                                      _f: F) -> EncoderResult
                                      where F : FnOnce(&mut Encoder) -> EncoderResult  {
        Err(UnsupportedType)
    }

    fn emit_struct< F >(&mut self,
                   _name: &str,
                   _len: usize,
                   f: F) -> EncoderResult
                   where F : FnOnce(&mut Encoder) -> EncoderResult  {
        self.data.push(Map(HashMap::new()));
        f(self)
    }

    fn emit_struct_field< F >(&mut self,
                         name: &str,
                         _idx: usize,
                         f: F) -> EncoderResult
                         where F : FnOnce(&mut Encoder) -> EncoderResult {
        let mut m = match self.data.pop() {
            Some(Map(m)) => m,
            _ => { return Err(UnsupportedType); }
        };
        try!(f(self));
        let data = match self.data.pop() {
            Some(d) => d,
            _ => { return Err(UnsupportedType); }
        };
        m.insert(name.to_string(), data);
        self.data.push(Map(m));
        Ok(())
    }

    fn emit_tuple< F >(&mut self,
                  len: usize,
                  f: F) -> EncoderResult
                  where F : FnOnce(&mut Encoder) -> EncoderResult {
        self.emit_seq(len, f)
    }

    fn emit_tuple_arg< F >(&mut self, idx: usize, f: F) -> EncoderResult
    where F : FnOnce(&mut Encoder) -> EncoderResult {
        self.emit_seq_elt(idx, f)
    }

    fn emit_tuple_struct< F >(&mut self,
                         _name: &str,
                         len: usize,
                         f: F) -> EncoderResult
                         where F : FnOnce(&mut Encoder) -> EncoderResult {
        self.emit_seq(len, f)
    }

    fn emit_tuple_struct_arg< F >(&mut self, idx: usize, f: F) -> EncoderResult
    where F : FnOnce(&mut Encoder) -> EncoderResult  {
        self.emit_seq_elt(idx, f)
    }

    // Specialized types:
    fn emit_option< F >(&mut self, f: F) -> EncoderResult
    where F : FnOnce(&mut Encoder) -> EncoderResult  {
        f(self)
    }

    fn emit_option_none(&mut self) -> EncoderResult {
        self.data.push(OptVal(None));
        Ok(())
    }

    fn emit_option_some< F >(&mut self, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder) -> EncoderResult {
        try!(f(self));
        let val = match self.data.pop() {
            Some(OptVal(_)) => { return Err(NestedOptions) },
            Some(d) => d,
            _ => { return Err(UnsupportedType); }
        };
        self.data.push(OptVal(Some(Box::new(val))));
        Ok(())
    }

    fn emit_seq< F >(&mut self, _len: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder) -> EncoderResult {
        self.data.push(VecVal(Vec::new()));
        f(self)
    }

    fn emit_seq_elt< F >(&mut self, _idx: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder) -> EncoderResult {
        let mut v = match self.data.pop() {
            Some(VecVal(v)) => v,
            _ => { return Err(UnsupportedType); }
        };
        try!(f(self));
        let data = match self.data.pop() {
            Some(d) => d,
            _ => { return Err(UnsupportedType); }
        };
        v.push(data);
        self.data.push(VecVal(v));
        Ok(())
    }

    fn emit_map< F >(&mut self, _len: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder) -> EncoderResult {
        self.data.push(Map(HashMap::new()));
        f(self)
    }

    fn emit_map_elt_key< F >(&mut self, _idx: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder) -> EncoderResult {
        try!(f(self));
        let last = match self.data.last() {
            Some(d) => d,
            None => { return Err(MissingElements); }
        };
        match *last {
            StrVal(_) => Ok(()),
            _ => Err(KeyIsNotString),
        }
    }

    fn emit_map_elt_val< F >(&mut self, _idx: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder) -> EncoderResult {
        let k = match self.data.pop() {
            Some(StrVal(s)) => s,
            _ => { return Err(KeyIsNotString); }
        };
        let mut m = match self.data.pop() {
            Some(Map(m)) => m,
            _ => panic!("Expected a map"),
        };
        try!(f(self));
        let popped = match self.data.pop() {
            Some(p) => p,
            None => panic!("Error: Nothing to pop!"),
        };
        m.insert(k, popped);
        self.data.push(Map(m));
        Ok(())
    }
}

pub fn encode<'a, T: rustc_serialize::Encodable>(data: &T) -> Result<Data, Error> {
    let mut encoder = Encoder::new();
    try!(data.encode(&mut encoder));
    assert_eq!(encoder.data.len(), 1);
    match encoder.data.pop() {
        Some(data) => Ok(data),
        None => panic!("Error: Nothing to pop!"),
    }
}
<commit_msg>feat(encoder): support using encoder::Error as Box<std::error::Error><commit_after>use std::collections::HashMap;
use std::fmt;
use std::io::Error as StdIoError;
use std::error;
use std::iter::repeat;
use rustc_serialize;

use super::{Data, StrVal, Bool, VecVal, Map, OptVal};
pub use self::Error::*;

pub struct Encoder {
    pub data: Vec<Data>,
}

impl Encoder {
    pub fn new() -> Encoder {
        Encoder { data: Vec::new() }
    }
}

#[derive(Debug)]
pub enum Error {
    NestedOptions,
    UnsupportedType,
    InvalidStr,
    MissingElements,
    KeyIsNotString,
    NoFilename,
    IoError(StdIoError),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::error::Error;
        self.description().fmt(f)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use std::error::Error;
        match *self {
            NestedOptions => "nested Option types are not supported",
            UnsupportedType => "unsupported type",
            InvalidStr => "invalid str",
            MissingElements => "no elements in value",
            KeyIsNotString => "key is not a string",
            NoFilename => "a filename must be provided",
            IoError(ref err) => err.description(),
        }
    }
}

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

pub type EncoderResult = Result<(), Error>;

impl rustc_serialize::Encoder for Encoder {
    type Error = Error;

    fn emit_nil(&mut self) -> EncoderResult { Err(UnsupportedType) }

    fn emit_isize(&mut self, v: isize) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_usize(&mut self, v: usize) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u64(&mut self, v: u64) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u32(&mut self, v: u32) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u16(&mut self, v: u16) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_u8(&mut self, v: u8) -> EncoderResult     { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_i64(&mut self, v: i64) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_i32(&mut self, v: i32) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_i16(&mut self, v: i16) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_i8(&mut self, v: i8) -> EncoderResult   { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_bool(&mut self, v: bool) -> EncoderResult { self.data.push(Bool(v)); Ok(()) }

    fn emit_f64(&mut self, v: f64) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }
    fn emit_f32(&mut self, v: f32) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_char(&mut self, v: char) -> EncoderResult {
        self.data.push(StrVal(repeat(v).take(1).collect::<String>()));
        Ok(())
    }
    fn emit_str(&mut self, v: &str) -> EncoderResult { self.data.push(StrVal(v.to_string())); Ok(()) }

    fn emit_enum< F >(&mut self, _name: &str, _f: F ) -> EncoderResult
    where F : FnOnce(&mut Encoder) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_variant< F >(&mut self,
                         _name: &str,
                         _id: usize,
                         _len: usize,
                         _f: F) -> EncoderResult
                         where F : FnOnce(&mut Encoder) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_variant_arg< F >(&mut self,
                             _a_idx: usize,
                             _f: F) -> EncoderResult
                             where F : FnOnce(&mut Encoder) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_struct_variant< F >(&mut self,
                                _v_name: &str,
                                _v_id: usize,
                                _len: usize,
                                _f: F) -> EncoderResult
                                where F : FnOnce(&mut Encoder) -> EncoderResult {
        Err(UnsupportedType)
    }

    fn emit_enum_struct_variant_field< F >(&mut self,
                                      _f_name: &str,
                                      _f_idx: usize,
                                      _f: F) -> EncoderResult
                                      where F : FnOnce(&mut Encoder) -> EncoderResult  {
        Err(UnsupportedType)
    }

    fn emit_struct< F >(&mut self,
                   _name: &str,
                   _len: usize,
                   f: F) -> EncoderResult
                   where F : FnOnce(&mut Encoder) -> EncoderResult  {
        self.data.push(Map(HashMap::new()));
        f(self)
    }

    fn emit_struct_field< F >(&mut self,
                         name: &str,
                         _idx: usize,
                         f: F) -> EncoderResult
                         where F : FnOnce(&mut Encoder) -> EncoderResult {
        let mut m = match self.data.pop() {
            Some(Map(m)) => m,
            _ => { return Err(UnsupportedType); }
        };
        try!(f(self));
        let data = match self.data.pop() {
            Some(d) => d,
            _ => { return Err(UnsupportedType); }
        };
        m.insert(name.to_string(), data);
        self.data.push(Map(m));
        Ok(())
    }

    fn emit_tuple< F >(&mut self,
                  len: usize,
                  f: F) -> EncoderResult
                  where F : FnOnce(&mut Encoder) -> EncoderResult {
        self.emit_seq(len, f)
    }

    fn emit_tuple_arg< F >(&mut self, idx: usize, f: F) -> EncoderResult
    where F : FnOnce(&mut Encoder) -> EncoderResult {
        self.emit_seq_elt(idx, f)
    }

    fn emit_tuple_struct< F >(&mut self,
                         _name: &str,
                         len: usize,
                         f: F) -> EncoderResult
                         where F : FnOnce(&mut Encoder) -> EncoderResult {
        self.emit_seq(len, f)
    }

    fn emit_tuple_struct_arg< F >(&mut self, idx: usize, f: F) -> EncoderResult
    where F : FnOnce(&mut Encoder) -> EncoderResult  {
        self.emit_seq_elt(idx, f)
    }

    // Specialized types:
    fn emit_option< F >(&mut self, f: F) -> EncoderResult
    where F : FnOnce(&mut Encoder) -> EncoderResult  {
        f(self)
    }

    fn emit_option_none(&mut self) -> EncoderResult {
        self.data.push(OptVal(None));
        Ok(())
    }

    fn emit_option_some< F >(&mut self, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder) -> EncoderResult {
        try!(f(self));
        let val = match self.data.pop() {
            Some(OptVal(_)) => { return Err(NestedOptions) },
            Some(d) => d,
            _ => { return Err(UnsupportedType); }
        };
        self.data.push(OptVal(Some(Box::new(val))));
        Ok(())
    }

    fn emit_seq< F >(&mut self, _len: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder) -> EncoderResult {
        self.data.push(VecVal(Vec::new()));
        f(self)
    }

    fn emit_seq_elt< F >(&mut self, _idx: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder) -> EncoderResult {
        let mut v = match self.data.pop() {
            Some(VecVal(v)) => v,
            _ => { return Err(UnsupportedType); }
        };
        try!(f(self));
        let data = match self.data.pop() {
            Some(d) => d,
            _ => { return Err(UnsupportedType); }
        };
        v.push(data);
        self.data.push(VecVal(v));
        Ok(())
    }

    fn emit_map< F >(&mut self, _len: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder) -> EncoderResult {
        self.data.push(Map(HashMap::new()));
        f(self)
    }

    fn emit_map_elt_key< F >(&mut self, _idx: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder) -> EncoderResult {
        try!(f(self));
        let last = match self.data.last() {
            Some(d) => d,
            None => { return Err(MissingElements); }
        };
        match *last {
            StrVal(_) => Ok(()),
            _ => Err(KeyIsNotString),
        }
    }

    fn emit_map_elt_val< F >(&mut self, _idx: usize, f: F) -> EncoderResult
  where F : FnOnce(&mut Encoder) -> EncoderResult {
        let k = match self.data.pop() {
            Some(StrVal(s)) => s,
            _ => { return Err(KeyIsNotString); }
        };
        let mut m = match self.data.pop() {
            Some(Map(m)) => m,
            _ => panic!("Expected a map"),
        };
        try!(f(self));
        let popped = match self.data.pop() {
            Some(p) => p,
            None => panic!("Error: Nothing to pop!"),
        };
        m.insert(k, popped);
        self.data.push(Map(m));
        Ok(())
    }
}

pub fn encode<'a, T: rustc_serialize::Encodable>(data: &T) -> Result<Data, Error> {
    let mut encoder = Encoder::new();
    try!(data.encode(&mut encoder));
    assert_eq!(encoder.data.len(), 1);
    match encoder.data.pop() {
        Some(data) => Ok(data),
        None => panic!("Error: Nothing to pop!"),
    }
}
<|endoftext|>


<commit_before>//! This module is dedicated to calculating the fitness of moon landing programs
use moonlander_gp::{AstNode, depth, ScoreCard, Number, Fitness};
use moonlander_gp::num::square;
use super::sim::{SensorData, World, apply_command,EvaluateToCommand, LandingTrace};
use rand::Rng;

pub fn score_lander<P>(program: &P, _: &mut Rng, mut sensor_data: SensorData, world: &World) -> LandingTrace
    where P: EvaluateToCommand+AstNode
{
    let mut trace : Vec<SensorData> = Vec::with_capacity(100);
    let mut total_height: Number = 0.;
    let mut total_fuel: Number = 0.;

    trace.push(sensor_data);
    while !sensor_data.hit_ground {
        total_height += square(sensor_data.y);
        total_fuel += square(sensor_data.fuel);

        let command = program.evaluate(&sensor_data);
        apply_command(&mut sensor_data, command, world);

        trace.push(sensor_data);
    };

    let frames = trace.len() as Number;
    LandingTrace {
        trace: trace,
        score_card: ScoreCard::new(vec![
            ("survival_bonus",   3.0 * frames),
            ("height_penalty",   -(0.01 * total_height / frames)),
            ("fuel_bonus",        (100.0 * total_fuel / frames)),
            ("hit_ground_bonus", if sensor_data.hit_ground { 10.0 } else { 0.0 }),
            ("crash_penalty",    sensor_data.crash_speed),
            ("success_bonus",    if sensor_data.landed { 10000.0 } else { 0.0 }),
            ("complexity_pentalty", depth(program) as f32 * -5.0)
        ])
    }
}

/// Score the lander multiple times and combines the scores
///
/// Returns the best trace and the average score
pub fn score_lander_multi<P, G>(n: usize, program: &P, rng: &mut Rng, sensor_data_fn: G, world: &World) -> LandingTrace
    where P : EvaluateToCommand+AstNode,
          G : Fn(&mut Rng) -> SensorData
{
    let mut best_trace = LandingTrace::new();
    let mut total_score = ScoreCard::new(vec![]);
    for _ in 0..n {
        let initial = sensor_data_fn(rng);
        let trace = score_lander(program, rng, initial, world);
        total_score += trace.score_card();
        if trace.score_card() > best_trace.score_card() {
            best_trace = trace;
        }
    }

    let average_score = total_score / (n as Number);

    LandingTrace { trace: best_trace.trace, score_card: average_score }
}
<commit_msg>Take negative scores into account<commit_after>//! This module is dedicated to calculating the fitness of moon landing programs
use moonlander_gp::{AstNode, depth, ScoreCard, Number, Fitness};
use moonlander_gp::num::square;
use super::sim::{SensorData, World, apply_command,EvaluateToCommand, LandingTrace};
use rand::Rng;

pub fn score_lander<P>(program: &P, _: &mut Rng, mut sensor_data: SensorData, world: &World) -> LandingTrace
    where P: EvaluateToCommand+AstNode
{
    let mut trace : Vec<SensorData> = Vec::with_capacity(100);
    let mut total_height: Number = 0.;
    let mut total_fuel: Number = 0.;

    trace.push(sensor_data);
    while !sensor_data.hit_ground {
        total_height += square(sensor_data.y);
        total_fuel += square(sensor_data.fuel);

        let command = program.evaluate(&sensor_data);
        apply_command(&mut sensor_data, command, world);

        trace.push(sensor_data);
    };

    let frames = trace.len() as Number;
    LandingTrace {
        trace: trace,
        score_card: ScoreCard::new(vec![
            ("survival_bonus",   3.0 * frames),
            ("height_penalty",   -(0.01 * total_height / frames)),
            ("fuel_bonus",        (100.0 * total_fuel / frames)),
            ("hit_ground_bonus", if sensor_data.hit_ground { 10.0 } else { 0.0 }),
            ("crash_penalty",    sensor_data.crash_speed),
            ("success_bonus",    if sensor_data.landed { 10000.0 } else { 0.0 }),
            ("complexity_pentalty", depth(program) as f32 * -5.0)
        ])
    }
}

/// Score the lander multiple times and combines the scores
///
/// Returns the best trace and the average score
pub fn score_lander_multi<P, G>(n: usize, program: &P, rng: &mut Rng, sensor_data_fn: G, world: &World) -> LandingTrace
    where P : EvaluateToCommand+AstNode,
          G : Fn(&mut Rng) -> SensorData
{
    let mut best_trace = LandingTrace::new();
    let mut total_score = ScoreCard::new(vec![]);
    for _ in 0..n {
        let initial = sensor_data_fn(rng);
        let trace = score_lander(program, rng, initial, world);
        total_score += trace.score_card();
        if trace.score_card() > best_trace.score_card() || best_trace.score_card().is_empty() {
            best_trace = trace;
        }
    }

    let average_score = total_score / (n as Number);

    LandingTrace { trace: best_trace.trace, score_card: average_score }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Unix-specific utilities for working with the filesystem.

use std::ffi::{OsStr, OsString};
use std::path::Path;

use log::warn;

/// An extended attribute of a file.
///
/// On Linux, extended attributes can be obtained using `getfattr` and set with
/// `setfattr` utilities. On macOS, they can be manipulated through `getxattr`
/// and `setxattr` utilities.
///
/// See the [Wikipedia] article for more details.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Extended_file_attributes
pub struct ExtAttr {
    /// A name of the extended attribute.
    pub name: OsString,
    /// A value of the extended attribute.
    pub value: Option<Vec<u8>>,
}

/// Returns an iterator over extended attributes of the specified file.
///
/// # Errors
///
/// The function will fail if a list of extended attributes of the file cannot
/// be obtained (e.g. when the file doesn't exist). However, all errors when
/// that can occur when inspecting values for particular attribute are logged
/// and forgotten.
///
/// # Examples
///
/// ```no_run
/// for attr in rrg::fs::unix::ext_attrs(&"/tmp/foo").unwrap() {
///     let name = attr.name.to_string_lossy();
///     match attr.value {
///         Some(value) => println!("{}: {:?}", name, value),
///         None => println!("{}", name),
///     }
/// }
/// ```
pub fn ext_attrs<'p, P>(path: &'p P) -> std::io::Result<ExtAttrs<'p>>
where
    P: AsRef<Path>,
{
    let iter = xattr::list(&path)?;

    Ok(ExtAttrs {
        path: path.as_ref(),
        iter: iter,
    })
}

/// Iterator over extended attributes of a file.
///
/// Note that this iterator always returns an attribute. All errors that can
/// occur when obtaining values for particular attributes are swallowed.
///
/// The iterator can be constructed with the [`ext_attrs`] function.
///
/// [`ext_attrs`]: fn.ext_attrs.html
pub struct ExtAttrs<'p> {
    path: &'p Path,
    iter: xattr::XAttrs,
}

impl<'p> Iterator for ExtAttrs<'p> {

    type Item = ExtAttr;

    fn next(&mut self) -> Option<ExtAttr> {
        for name in &mut self.iter {
            let value = match ext_attr_value(self.path, &name) {
                Ok(value) => value,
                Err(()) => continue,
            };

            return Some(ExtAttr {
                name: name,
                value: value,
            });
        }

        None
    }
}

/// Collects value of an extended attribute with the specified name.
///
/// This is a tiny wrapper around `xattr::get`, but logs and forgets the error
/// (if occurs).
fn ext_attr_value<P>(path: P, name: &OsStr) -> Result<Option<Vec<u8>>, ()>
where
    P: AsRef<Path>,
{
    xattr::get(&path, name).map_err(|error| warn! {
        "failed to collect attribute '{:?}' of '{path}': {cause}",
        name = name,
        path = path.as_ref().display(),
        cause = error,
    })
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_ext_attrs_non_existing() {
        let tempdir = tempfile::tempdir().unwrap();

        assert!(ext_attrs(&tempdir.path().join("foo")).is_err());
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    #[test]
    fn test_ext_attrs_with_multiple_values() {
        let tempdir = tempfile::tempdir().unwrap();
        let tempfile = tempdir.path().join("foo");
        std::fs::File::create(&tempfile).unwrap();

        assert! {
            std::process::Command::new("setfattr")
                .arg("--name").arg("user.abc")
                .arg("--value").arg("quux")
                .arg(&tempfile)
                .status()
                .unwrap()
                .success()
        };

        assert! {
            std::process::Command::new("setfattr")
                .arg("--name").arg("user.def")
                .arg("--value").arg("norf")
                .arg(&tempfile)
                .status()
                .unwrap()
                .success()
        };

        let mut results = ext_attrs(&tempfile).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|attr| attr.name.clone());

        assert_eq!(results.len(), 2);

        assert_eq!(results[0].name, "user.abc");
        assert_eq!(results[0].value, Some("quux".into()));

        assert_eq!(results[1].name, "user.def");
        assert_eq!(results[1].value, Some("norf".into()));
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    #[test]
    fn test_ext_attrs_with_empty_value() {
        let tempdir = tempfile::tempdir().unwrap();
        let tempfile = tempdir.path().join("foo");
        std::fs::File::create(&tempfile).unwrap();

        assert! {
            std::process::Command::new("setfattr")
                .arg("--name").arg("user.abc")
                .arg(&tempfile)
                .status()
                .unwrap()
                .success()
        };

        let mut iter = ext_attrs(&tempfile).unwrap();

        let attr = iter.next().unwrap();
        assert_eq!(attr.name, "user.abc");
        assert_eq!(attr.value, Some("".into()));

        assert!(iter.next().is_none());
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    #[test]
    fn test_ext_attrs_with_bytes_value() {
        use std::os::unix::ffi::OsStrExt as _;

        let tempdir = tempfile::tempdir().unwrap();
        let tempfile = tempdir.path().join("foo");
        std::fs::File::create(&tempfile).unwrap();

        assert! {
            std::process::Command::new("setfattr")
                .arg("--name").arg("user.abc")
                .arg("--value").arg(OsStr::from_bytes(b"\xff\xfe\xff\xfe\xff"))
                .arg(&tempfile)
                .status()
                .unwrap()
                .success()
        };

        let mut iter = ext_attrs(&tempfile).unwrap();

        let attr = iter.next().unwrap();
        assert_eq!(attr.name, "user.abc");
        assert_eq!(attr.value, Some(b"\xff\xfe\xff\xfe\xff".to_vec()));

        assert!(iter.next().is_none());
    }

    // TODO: Add macOS tests.
}

// TODO: Move this into the `rrg-proto` crate once generic purpose utilities are
// moved to a separate crate.
impl Into<rrg_proto::stat_entry::ExtAttr> for ExtAttr {

    fn into(self) -> rrg_proto::stat_entry::ExtAttr {
        use std::os::unix::ffi::OsStringExt as _;

        rrg_proto::stat_entry::ExtAttr {
            name: Some(self.name.into_vec()),
            value: self.value,
        }
    }
}
<commit_msg>Derive the `Debug` trait for extended attributes.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Unix-specific utilities for working with the filesystem.

use std::ffi::{OsStr, OsString};
use std::path::Path;

use log::warn;

/// An extended attribute of a file.
///
/// On Linux, extended attributes can be obtained using `getfattr` and set with
/// `setfattr` utilities. On macOS, they can be manipulated through `getxattr`
/// and `setxattr` utilities.
///
/// See the [Wikipedia] article for more details.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Extended_file_attributes
#[derive(Debug)]
pub struct ExtAttr {
    /// A name of the extended attribute.
    pub name: OsString,
    /// A value of the extended attribute.
    pub value: Option<Vec<u8>>,
}

/// Returns an iterator over extended attributes of the specified file.
///
/// # Errors
///
/// The function will fail if a list of extended attributes of the file cannot
/// be obtained (e.g. when the file doesn't exist). However, all errors when
/// that can occur when inspecting values for particular attribute are logged
/// and forgotten.
///
/// # Examples
///
/// ```no_run
/// for attr in rrg::fs::unix::ext_attrs(&"/tmp/foo").unwrap() {
///     let name = attr.name.to_string_lossy();
///     match attr.value {
///         Some(value) => println!("{}: {:?}", name, value),
///         None => println!("{}", name),
///     }
/// }
/// ```
pub fn ext_attrs<'p, P>(path: &'p P) -> std::io::Result<ExtAttrs<'p>>
where
    P: AsRef<Path>,
{
    let iter = xattr::list(&path)?;

    Ok(ExtAttrs {
        path: path.as_ref(),
        iter: iter,
    })
}

/// Iterator over extended attributes of a file.
///
/// Note that this iterator always returns an attribute. All errors that can
/// occur when obtaining values for particular attributes are swallowed.
///
/// The iterator can be constructed with the [`ext_attrs`] function.
///
/// [`ext_attrs`]: fn.ext_attrs.html
pub struct ExtAttrs<'p> {
    path: &'p Path,
    iter: xattr::XAttrs,
}

impl<'p> Iterator for ExtAttrs<'p> {

    type Item = ExtAttr;

    fn next(&mut self) -> Option<ExtAttr> {
        for name in &mut self.iter {
            let value = match ext_attr_value(self.path, &name) {
                Ok(value) => value,
                Err(()) => continue,
            };

            return Some(ExtAttr {
                name: name,
                value: value,
            });
        }

        None
    }
}

/// Collects value of an extended attribute with the specified name.
///
/// This is a tiny wrapper around `xattr::get`, but logs and forgets the error
/// (if occurs).
fn ext_attr_value<P>(path: P, name: &OsStr) -> Result<Option<Vec<u8>>, ()>
where
    P: AsRef<Path>,
{
    xattr::get(&path, name).map_err(|error| warn! {
        "failed to collect attribute '{:?}' of '{path}': {cause}",
        name = name,
        path = path.as_ref().display(),
        cause = error,
    })
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_ext_attrs_non_existing() {
        let tempdir = tempfile::tempdir().unwrap();

        assert!(ext_attrs(&tempdir.path().join("foo")).is_err());
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    #[test]
    fn test_ext_attrs_with_multiple_values() {
        let tempdir = tempfile::tempdir().unwrap();
        let tempfile = tempdir.path().join("foo");
        std::fs::File::create(&tempfile).unwrap();

        assert! {
            std::process::Command::new("setfattr")
                .arg("--name").arg("user.abc")
                .arg("--value").arg("quux")
                .arg(&tempfile)
                .status()
                .unwrap()
                .success()
        };

        assert! {
            std::process::Command::new("setfattr")
                .arg("--name").arg("user.def")
                .arg("--value").arg("norf")
                .arg(&tempfile)
                .status()
                .unwrap()
                .success()
        };

        let mut results = ext_attrs(&tempfile).unwrap().collect::<Vec<_>>();
        results.sort_by_key(|attr| attr.name.clone());

        assert_eq!(results.len(), 2);

        assert_eq!(results[0].name, "user.abc");
        assert_eq!(results[0].value, Some("quux".into()));

        assert_eq!(results[1].name, "user.def");
        assert_eq!(results[1].value, Some("norf".into()));
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    #[test]
    fn test_ext_attrs_with_empty_value() {
        let tempdir = tempfile::tempdir().unwrap();
        let tempfile = tempdir.path().join("foo");
        std::fs::File::create(&tempfile).unwrap();

        assert! {
            std::process::Command::new("setfattr")
                .arg("--name").arg("user.abc")
                .arg(&tempfile)
                .status()
                .unwrap()
                .success()
        };

        let mut iter = ext_attrs(&tempfile).unwrap();

        let attr = iter.next().unwrap();
        assert_eq!(attr.name, "user.abc");
        assert_eq!(attr.value, Some("".into()));

        assert!(iter.next().is_none());
    }

    #[cfg(all(target_os = "linux", feature = "test-setfattr"))]
    #[test]
    fn test_ext_attrs_with_bytes_value() {
        use std::os::unix::ffi::OsStrExt as _;

        let tempdir = tempfile::tempdir().unwrap();
        let tempfile = tempdir.path().join("foo");
        std::fs::File::create(&tempfile).unwrap();

        assert! {
            std::process::Command::new("setfattr")
                .arg("--name").arg("user.abc")
                .arg("--value").arg(OsStr::from_bytes(b"\xff\xfe\xff\xfe\xff"))
                .arg(&tempfile)
                .status()
                .unwrap()
                .success()
        };

        let mut iter = ext_attrs(&tempfile).unwrap();

        let attr = iter.next().unwrap();
        assert_eq!(attr.name, "user.abc");
        assert_eq!(attr.value, Some(b"\xff\xfe\xff\xfe\xff".to_vec()));

        assert!(iter.next().is_none());
    }

    // TODO: Add macOS tests.
}

// TODO: Move this into the `rrg-proto` crate once generic purpose utilities are
// moved to a separate crate.
impl Into<rrg_proto::stat_entry::ExtAttr> for ExtAttr {

    fn into(self) -> rrg_proto::stat_entry::ExtAttr {
        use std::os::unix::ffi::OsStringExt as _;

        rrg_proto::stat_entry::ExtAttr {
            name: Some(self.name.into_vec()),
            value: self.value,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use std::sync::Arc;

use libfuzzer_sys::arbitrary::{Arbitrary, Error, Unstructured};

use crate::prelude::*;

// Adding new fuzz targets
//
// 1. Add a function to this file which looks like this:
//
//    pub fn fuzz_something(data: Data) {
//      // Invoke everything you need.
//      //
//      // Your function may accept a value of any type that implements
//      // Arbitrary [1]. This is how fuzzer affects the execution—by
//      // feeding in different bytes, which result in different
//      // arbitrary values being generated.
//      // [1]: https://docs.rs/arbitrary/0.3.3/arbitrary/trait.Arbitrary.html
//      //
//      // Derive Debug for the structures you create with arbitrary data.
//    }
//
// 2. cargo fuzz add something
// 3. Copy the contents of any other .rs file from fuzz/fuzz_targets/ into the
//    newly created fuzz/fuzz_targets/something.rs and change the function
//    being called to fuzz_something.
//
// Now you can fuzz the new target with cargo fuzz.

#[derive(Debug)]
pub struct ArbitraryConfig {
  config: Config,
}

#[inline]
fn arbitrary_rational(u: &mut Unstructured<'_>) -> Result<Rational, Error> {
  Ok(Rational::new(Arbitrary::arbitrary(u)?, Arbitrary::arbitrary(u)?))
}

impl Arbitrary for ArbitraryConfig {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut enc = EncoderConfig::with_speed_preset(Arbitrary::arbitrary(u)?);
    enc.width = Arbitrary::arbitrary(u)?;
    enc.height = Arbitrary::arbitrary(u)?;
    enc.bit_depth = u.int_in_range(0..=16)?;
    enc.still_picture = Arbitrary::arbitrary(u)?;
    enc.time_base = arbitrary_rational(u)?;
    enc.min_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.max_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.reservoir_frame_delay = Arbitrary::arbitrary(u)?;
    enc.low_latency = Arbitrary::arbitrary(u)?;
    enc.quantizer = Arbitrary::arbitrary(u)?;
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
    enc.bitrate = Arbitrary::arbitrary(u)?;
    enc.tile_cols = Arbitrary::arbitrary(u)?;
    enc.tile_rows = Arbitrary::arbitrary(u)?;
    enc.tiles = Arbitrary::arbitrary(u)?;
    enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config })
  }
}

pub fn fuzz_construct_context(arbitrary: ArbitraryConfig) {
  let _: Result<Context<u16>, _> = arbitrary.config.new_context();
}

fn encode_frames(
  ctx: &mut Context<u8>, mut frames: impl Iterator<Item = Frame<u8>>,
) -> Result<(), EncoderStatus> {
  loop {
    let rv = ctx.receive_packet();
    debug!("ctx.receive_packet() = {:#?}", rv);

    match rv {
      Ok(_packet) => {}
      Err(EncoderStatus::Encoded) => {}
      Err(EncoderStatus::LimitReached) => {
        break;
      }
      Err(EncoderStatus::NeedMoreData) => {
        ctx.send_frame(frames.next().map(Arc::new))?;
      }
      Err(EncoderStatus::EnoughData) => {
        unreachable!();
      }
      Err(EncoderStatus::NotReady) => {
        unreachable!();
      }
      Err(EncoderStatus::Failure) => {
        return Err(EncoderStatus::Failure);
      }
    }
  }

  Ok(())
}

#[derive(Debug)]
pub struct ArbitraryEncoder {
  config: Config,
  frame_count: u8,
  pixels: Box<[u8]>,
}

impl Arbitrary for ArbitraryEncoder {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut enc = EncoderConfig::with_speed_preset(u.int_in_range(0..=10)?);
    enc.width = u.int_in_range(1..=256)?;
    enc.height = u.int_in_range(1..=256)?;
    enc.still_picture = Arbitrary::arbitrary(u)?;
    enc.time_base = arbitrary_rational(u)?;
    enc.min_key_frame_interval = u.int_in_range(0..=3)?;
    enc.max_key_frame_interval = u.int_in_range(1..=4)?;
    enc.low_latency = Arbitrary::arbitrary(u)?;
    enc.quantizer = Arbitrary::arbitrary(u)?;
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
    enc.bitrate = Arbitrary::arbitrary(u)?;
    enc.tile_cols = u.int_in_range(0..=2)?;
    enc.tile_rows = u.int_in_range(0..=2)?;
    enc.tiles = u.int_in_range(0..=16)?;
    enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;

    enc.chroma_sampling = *u.choose(&[
      ChromaSampling::Cs420,
      ChromaSampling::Cs422,
      ChromaSampling::Cs444,
      ChromaSampling::Cs400,
    ])?;
    enc.chroma_sample_position = *u.choose(&[
      ChromaSamplePosition::Unknown,
      ChromaSamplePosition::Vertical,
      ChromaSamplePosition::Colocated,
    ])?;
    enc.pixel_range = *u.choose(&[PixelRange::Limited, PixelRange::Full])?;
    enc.error_resilient = Arbitrary::arbitrary(u)?;
    enc.reservoir_frame_delay = Arbitrary::arbitrary(u)?;

    let frame_count =
      if enc.still_picture { 1 } else { u.int_in_range(1..=3)? };
    if u.is_empty() {
      return Err(Error::NotEnoughData);
    }
    let pixels = u.get_bytes(u.len())?.to_vec().into_boxed_slice();
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config, frame_count, pixels })
  }
}

pub fn fuzz_encode(arbitrary: ArbitraryEncoder) {
  let res = arbitrary.config.new_context();
  if res.is_err() {
    return;
  }
  let mut context: Context<u8> = res.unwrap();

  let mut pixels = arbitrary.pixels.iter().cycle();
  let mut frame = context.new_frame();
  let frames = (0..arbitrary.frame_count).map(|_| {
    for plane in &mut frame.planes {
      let stride = plane.cfg.stride;
      for row in plane.data_origin_mut().chunks_mut(stride) {
        for pixel in row {
          *pixel = *pixels.next().unwrap();
        }
      }
    }

    frame.clone()
  });

  let _ = encode_frames(&mut context, frames);
}

#[derive(Debug)]
pub struct DecodeTestParameters {
  w: usize,
  h: usize,
  speed: usize,
  q: usize,
  limit: usize,
  bit_depth: usize,
  chroma_sampling: ChromaSampling,
  min_keyint: u64,
  max_keyint: u64,
  switch_frame_interval: u64,
  low_latency: bool,
  error_resilient: bool,
  bitrate: i32,
  tile_cols_log2: usize,
  tile_rows_log2: usize,
  still_picture: bool,
}

impl Arbitrary for DecodeTestParameters {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut p = Self {
      w: u.int_in_range(16..=16 + 255)?,
      h: u.int_in_range(16..=16 + 255)?,
      speed: u.int_in_range(0..=10)?,
      q: u8::arbitrary(u)?.into(),
      limit: u.int_in_range(1..=3)?,
      bit_depth: 8,
      chroma_sampling: *u.choose(&[
        ChromaSampling::Cs420,
        ChromaSampling::Cs422,
        ChromaSampling::Cs444,
        ChromaSampling::Cs400,
      ])?,
      min_keyint: u.int_in_range(0..=3)?,
      max_keyint: u.int_in_range(1..=4)?,
      switch_frame_interval: 0,
      low_latency: bool::arbitrary(u)?,
      error_resilient: bool::arbitrary(u)?,
      bitrate: u16::arbitrary(u)?.into(),
      tile_cols_log2: u.int_in_range(0..=2)?,
      tile_rows_log2: u.int_in_range(0..=2)?,
      still_picture: bool::arbitrary(u)?,
    };
    if p.still_picture {
      p.limit = 1
    }
    Ok(p)
  }
}

#[cfg(feature = "decode_test_dav1d")]
pub fn fuzz_encode_decode(p: DecodeTestParameters) {
  use crate::test_encode_decode::*;

  let mut dec = get_decoder::<u8>("dav1d", p.w, p.h);
  dec.encode_decode(
    p.w,
    p.h,
    p.speed,
    p.q,
    p.limit,
    p.bit_depth,
    p.chroma_sampling,
    p.min_keyint,
    p.max_keyint,
    p.switch_frame_interval,
    p.low_latency,
    p.error_resilient,
    p.bitrate,
    p.tile_cols_log2,
    p.tile_rows_log2,
    p.still_picture,
  );
}
<commit_msg>fuzz: Increase coverage of encode_decode<commit_after>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use std::sync::Arc;

use libfuzzer_sys::arbitrary::{Arbitrary, Error, Unstructured};

use crate::prelude::*;

// Adding new fuzz targets
//
// 1. Add a function to this file which looks like this:
//
//    pub fn fuzz_something(data: Data) {
//      // Invoke everything you need.
//      //
//      // Your function may accept a value of any type that implements
//      // Arbitrary [1]. This is how fuzzer affects the execution—by
//      // feeding in different bytes, which result in different
//      // arbitrary values being generated.
//      // [1]: https://docs.rs/arbitrary/0.3.3/arbitrary/trait.Arbitrary.html
//      //
//      // Derive Debug for the structures you create with arbitrary data.
//    }
//
// 2. cargo fuzz add something
// 3. Copy the contents of any other .rs file from fuzz/fuzz_targets/ into the
//    newly created fuzz/fuzz_targets/something.rs and change the function
//    being called to fuzz_something.
//
// Now you can fuzz the new target with cargo fuzz.

#[derive(Debug)]
pub struct ArbitraryConfig {
  config: Config,
}

#[inline]
fn arbitrary_rational(u: &mut Unstructured<'_>) -> Result<Rational, Error> {
  Ok(Rational::new(Arbitrary::arbitrary(u)?, Arbitrary::arbitrary(u)?))
}

impl Arbitrary for ArbitraryConfig {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut enc = EncoderConfig::with_speed_preset(Arbitrary::arbitrary(u)?);
    enc.width = Arbitrary::arbitrary(u)?;
    enc.height = Arbitrary::arbitrary(u)?;
    enc.bit_depth = u.int_in_range(0..=16)?;
    enc.still_picture = Arbitrary::arbitrary(u)?;
    enc.time_base = arbitrary_rational(u)?;
    enc.min_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.max_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.reservoir_frame_delay = Arbitrary::arbitrary(u)?;
    enc.low_latency = Arbitrary::arbitrary(u)?;
    enc.quantizer = Arbitrary::arbitrary(u)?;
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
    enc.bitrate = Arbitrary::arbitrary(u)?;
    enc.tile_cols = Arbitrary::arbitrary(u)?;
    enc.tile_rows = Arbitrary::arbitrary(u)?;
    enc.tiles = Arbitrary::arbitrary(u)?;
    enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config })
  }
}

pub fn fuzz_construct_context(arbitrary: ArbitraryConfig) {
  let _: Result<Context<u16>, _> = arbitrary.config.new_context();
}

fn encode_frames(
  ctx: &mut Context<u8>, mut frames: impl Iterator<Item = Frame<u8>>,
) -> Result<(), EncoderStatus> {
  loop {
    let rv = ctx.receive_packet();
    debug!("ctx.receive_packet() = {:#?}", rv);

    match rv {
      Ok(_packet) => {}
      Err(EncoderStatus::Encoded) => {}
      Err(EncoderStatus::LimitReached) => {
        break;
      }
      Err(EncoderStatus::NeedMoreData) => {
        ctx.send_frame(frames.next().map(Arc::new))?;
      }
      Err(EncoderStatus::EnoughData) => {
        unreachable!();
      }
      Err(EncoderStatus::NotReady) => {
        unreachable!();
      }
      Err(EncoderStatus::Failure) => {
        return Err(EncoderStatus::Failure);
      }
    }
  }

  Ok(())
}

#[derive(Debug)]
pub struct ArbitraryEncoder {
  config: Config,
  frame_count: u8,
  pixels: Box<[u8]>,
}

impl Arbitrary for ArbitraryEncoder {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut enc = EncoderConfig::with_speed_preset(u.int_in_range(0..=10)?);
    enc.width = u.int_in_range(1..=256)?;
    enc.height = u.int_in_range(1..=256)?;
    enc.still_picture = Arbitrary::arbitrary(u)?;
    enc.time_base = arbitrary_rational(u)?;
    enc.min_key_frame_interval = u.int_in_range(0..=3)?;
    enc.max_key_frame_interval = u.int_in_range(1..=4)?;
    enc.low_latency = Arbitrary::arbitrary(u)?;
    enc.quantizer = Arbitrary::arbitrary(u)?;
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
    enc.bitrate = Arbitrary::arbitrary(u)?;
    enc.tile_cols = u.int_in_range(0..=2)?;
    enc.tile_rows = u.int_in_range(0..=2)?;
    enc.tiles = u.int_in_range(0..=16)?;
    enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;

    enc.chroma_sampling = *u.choose(&[
      ChromaSampling::Cs420,
      ChromaSampling::Cs422,
      ChromaSampling::Cs444,
      ChromaSampling::Cs400,
    ])?;
    enc.chroma_sample_position = *u.choose(&[
      ChromaSamplePosition::Unknown,
      ChromaSamplePosition::Vertical,
      ChromaSamplePosition::Colocated,
    ])?;
    enc.pixel_range = *u.choose(&[PixelRange::Limited, PixelRange::Full])?;
    enc.error_resilient = Arbitrary::arbitrary(u)?;
    enc.reservoir_frame_delay = Arbitrary::arbitrary(u)?;

    let frame_count =
      if enc.still_picture { 1 } else { u.int_in_range(1..=3)? };
    if u.is_empty() {
      return Err(Error::NotEnoughData);
    }
    let pixels = u.get_bytes(u.len())?.to_vec().into_boxed_slice();
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config, frame_count, pixels })
  }
}

pub fn fuzz_encode(arbitrary: ArbitraryEncoder) {
  let res = arbitrary.config.new_context();
  if res.is_err() {
    return;
  }
  let mut context: Context<u8> = res.unwrap();

  let mut pixels = arbitrary.pixels.iter().cycle();
  let mut frame = context.new_frame();
  let frames = (0..arbitrary.frame_count).map(|_| {
    for plane in &mut frame.planes {
      let stride = plane.cfg.stride;
      for row in plane.data_origin_mut().chunks_mut(stride) {
        for pixel in row {
          *pixel = *pixels.next().unwrap();
        }
      }
    }

    frame.clone()
  });

  let _ = encode_frames(&mut context, frames);
}

#[derive(Debug)]
pub struct DecodeTestParameters {
  w: usize,
  h: usize,
  speed: usize,
  q: usize,
  limit: usize,
  bit_depth: usize,
  chroma_sampling: ChromaSampling,
  min_keyint: u64,
  max_keyint: u64,
  switch_frame_interval: u64,
  low_latency: bool,
  error_resilient: bool,
  bitrate: i32,
  tile_cols_log2: usize,
  tile_rows_log2: usize,
  still_picture: bool,
}

impl Arbitrary for DecodeTestParameters {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut p = Self {
      w: u.int_in_range(16..=16 + 255)?,
      h: u.int_in_range(16..=16 + 255)?,
      speed: u.int_in_range(0..=10)?,
      q: u8::arbitrary(u)?.into(),
      limit: u.int_in_range(1..=3)?,
      bit_depth: 8,
      chroma_sampling: *u.choose(&[
        ChromaSampling::Cs420,
        ChromaSampling::Cs422,
        ChromaSampling::Cs444,
        ChromaSampling::Cs400,
      ])?,
      min_keyint: u.int_in_range(0..=3)?,
      max_keyint: u.int_in_range(1..=4)?,
      switch_frame_interval: u.int_in_range(0..=3)?,
      low_latency: bool::arbitrary(u)?,
      error_resilient: bool::arbitrary(u)?,
      bitrate: u16::arbitrary(u)?.into(),
      tile_cols_log2: u.int_in_range(0..=2)?,
      tile_rows_log2: u.int_in_range(0..=2)?,
      still_picture: bool::arbitrary(u)?,
    };
    if !p.low_latency {
      p.switch_frame_interval = 0;
    }
    if p.still_picture {
      p.limit = 1
    }
    Ok(p)
  }
}

#[cfg(feature = "decode_test_dav1d")]
pub fn fuzz_encode_decode(p: DecodeTestParameters) {
  use crate::test_encode_decode::*;

  let mut dec = get_decoder::<u8>("dav1d", p.w, p.h);
  dec.encode_decode(
    p.w,
    p.h,
    p.speed,
    p.q,
    p.limit,
    p.bit_depth,
    p.chroma_sampling,
    p.min_keyint,
    p.max_keyint,
    p.switch_frame_interval,
    p.low_latency,
    p.error_resilient,
    p.bitrate,
    p.tile_cols_log2,
    p.tile_rows_log2,
    p.still_picture,
  );
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An efficient, low-level, bindless graphics API for Rust. See [the
//! blog](http://gfx-rs.github.io/) for explanations and annotated examples.

#![feature(core, libc, unsafe_destructor)]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
extern crate libc;
extern crate draw_state;

// draw state re-exports
pub use draw_state::{DrawState, BlendPreset};

// public re-exports
pub use render::{Renderer, DrawError};
pub use render::batch;
pub use render::device_ext::{DeviceExt, ShaderSource, ProgramError};
pub use render::mesh::{Attribute, Mesh, VertexFormat};
pub use render::mesh::Error as MeshError;
pub use render::mesh::{Slice, ToSlice, SliceKind};
pub use render::shade;
pub use render::target::{Frame, Plane};
pub use device::{Device, Resources};
pub use device::{attrib, tex};
pub use device::as_byte_slice;
pub use device::{BufferHandle, BufferInfo, RawBufferHandle, ShaderHandle};
pub use device::{ProgramHandle, SurfaceHandle, TextureHandle, SamplerHandle};
pub use device::BufferUsage;
pub use device::{VertexCount, InstanceCount};
pub use device::PrimitiveType;
pub use device::draw::CommandBuffer;
pub use device::shade::{ProgramInfo, UniformValue};
pub use draw_state::target::*;
pub use draw_state::block as state;

#[path = "../render/lib.rs"] pub mod render;
#[path = "../device/lib.rs"] pub mod device;

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D: device::Device> {
    /// Graphics device.
    pub device: D,
    /// Renderer front-end.
    pub renderer: Renderer<D::CommandBuffer>,
    /// Hidden batch context.
    context: batch::Context<D::Resources>,
}

impl<D: device::Device> std::ops::Deref for Graphics<D> {
    type Target = batch::Context<D::Resources>;

    fn deref(&self) -> &batch::Context<D::Resources> {
        &self.context
    }
}

impl<D: device::Device> Graphics<D> {
    /// Create a new graphics wrapper.
    pub fn new(mut device: D) -> Graphics<D> {
        let rend = device.create_renderer();
        Graphics {
            device: device,
            renderer: rend,
            context: batch::Context::new(),
        }
    }

    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: ClearData, mask: Mask, frame: &Frame<D::Resources>) {
        self.renderer.clear(data, mask, frame)
    }

    /// Draw a `RefBatch` batch.
    pub fn draw<'a, T: shade::ShaderParam<Resources = D::Resources>>(&'a mut self,
                batch: &'a batch::RefBatch<T>, frame: &Frame<D::Resources>)
                -> Result<(), DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&(batch, &self.context), frame)
    }

    /// Draw a `RefCore` batch.
    pub fn draw_core<'a, T: shade::ShaderParam<Resources = D::Resources>>(&'a mut self,
                     core: &'a batch::RefCore<T>, slice: &'a Slice<D::Resources>,
                     params: &'a T, frame: &Frame<D::Resources>)
                     -> Result<(), DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&self.context.bind(core, slice, params), frame)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
    }
}
<commit_msg>Implemented DerefMut for Graphics<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An efficient, low-level, bindless graphics API for Rust. See [the
//! blog](http://gfx-rs.github.io/) for explanations and annotated examples.

#![feature(core, libc, unsafe_destructor)]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
extern crate libc;
extern crate draw_state;

// draw state re-exports
pub use draw_state::{DrawState, BlendPreset};

// public re-exports
pub use render::{Renderer, DrawError};
pub use render::batch;
pub use render::device_ext::{DeviceExt, ShaderSource, ProgramError};
pub use render::mesh::{Attribute, Mesh, VertexFormat};
pub use render::mesh::Error as MeshError;
pub use render::mesh::{Slice, ToSlice, SliceKind};
pub use render::shade;
pub use render::target::{Frame, Plane};
pub use device::{Device, Resources};
pub use device::{attrib, tex};
pub use device::as_byte_slice;
pub use device::{BufferHandle, BufferInfo, RawBufferHandle, ShaderHandle};
pub use device::{ProgramHandle, SurfaceHandle, TextureHandle, SamplerHandle};
pub use device::BufferUsage;
pub use device::{VertexCount, InstanceCount};
pub use device::PrimitiveType;
pub use device::draw::CommandBuffer;
pub use device::shade::{ProgramInfo, UniformValue};
pub use draw_state::target::*;
pub use draw_state::block as state;

#[path = "../render/lib.rs"] pub mod render;
#[path = "../device/lib.rs"] pub mod device;

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D: device::Device> {
    /// Graphics device.
    pub device: D,
    /// Renderer front-end.
    pub renderer: Renderer<D::CommandBuffer>,
    /// Hidden batch context.
    context: batch::Context<D::Resources>,
}

impl<D: device::Device> std::ops::Deref for Graphics<D> {
    type Target = batch::Context<D::Resources>;

    fn deref(&self) -> &batch::Context<D::Resources> {
        &self.context
    }
}

impl<D: device::Device> std::ops::DerefMut for Graphics<D> {
    fn deref_mut(&mut self) -> &mut batch::Context<D::Resources> {
        &mut self.context
    }
}

impl<D: device::Device> Graphics<D> {
    /// Create a new graphics wrapper.
    pub fn new(mut device: D) -> Graphics<D> {
        let rend = device.create_renderer();
        Graphics {
            device: device,
            renderer: rend,
            context: batch::Context::new(),
        }
    }

    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: ClearData, mask: Mask, frame: &Frame<D::Resources>) {
        self.renderer.clear(data, mask, frame)
    }

    /// Draw a `RefBatch` batch.
    pub fn draw<'a, T: shade::ShaderParam<Resources = D::Resources>>(&'a mut self,
                batch: &'a batch::RefBatch<T>, frame: &Frame<D::Resources>)
                -> Result<(), DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&(batch, &self.context), frame)
    }

    /// Draw a `RefCore` batch.
    pub fn draw_core<'a, T: shade::ShaderParam<Resources = D::Resources>>(&'a mut self,
                     core: &'a batch::RefCore<T>, slice: &'a Slice<D::Resources>,
                     params: &'a T, frame: &Frame<D::Resources>)
                     -> Result<(), DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&self.context.bind(core, slice, params), frame)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
    }
}
<|endoftext|>