<commit_before>use csv;
use std::{cmp, error, fmt};
use std::error::Error;
use term_painter::{Attr, Color, ToStyle};
use term_size;
use textwrap;

#[derive(Clone, Debug)]
pub enum Location {
    FileLineColumn(String, usize, usize),
    FileRowField(String, usize, usize),
    FileLine(String, usize),
    File(String),
    Unspecified,
}

impl fmt::Display for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Location::FileLineColumn(ref file, line, col) => write!(f, "{}:{}:{}", file, line, col),
            Location::FileRowField(ref file, row, field) => {
                write!(f, "{}:{}[{}]", file, row, field)
            }
            Location::FileLine(ref file, line) => write!(f, "{}:{}]", file, line),
            Location::File(ref file) => write!(f, "{}", file),
            Location::Unspecified => Ok(()),
        }
    }
}

#[derive(Debug)]
pub struct ErrorWithLocation<E> {
    location: Location,
    error: E,
}

impl<E> ErrorWithLocation<E> {
    pub fn new<F: Into<E>>(location: Location, error: F) -> ErrorWithLocation<E> {
        ErrorWithLocation {
            location: location,
            error: error.into(),
        }
    }

    pub fn from_error<F: Into<E>>(other: F) -> ErrorWithLocation<E> {
        ErrorWithLocation::new(Location::Unspecified, other.into())
    }
}

impl<E: fmt::Display> ErrorWithLocation<E> {
    pub fn print_help(&self) {
        println!("{}{} {}",
                 Attr::Bold.paint((Color::Red.paint("error"))),
                 Attr::Bold.paint(":"),
                 Attr::Bold.paint(self.error()));
        match *self.location() {
            Location::Unspecified => (),
            _ => println!("  --> {}", Color::Yellow.paint(self.location())),
        }

        let dims = term_size::dimensions().unwrap_or((80, 25));

        let term_width = cmp::max(dims.0, 4);
        let out = textwrap::wrap(format!("{}", self.error).as_str(), term_width - 3)
            .into_iter()
            .map(|line| textwrap::indent(line.as_str(), "   "))
            .fold(String::new(), |s1, s2| s1 + s2.as_str());
        println!("{}", out);
    }
}

impl<E> ErrorWithLocation<E> {
    pub fn error(&self) -> &E {
        &self.error
    }

    pub fn into_error(self) -> E {
        self.error
    }

    pub fn location(&self) -> &Location {
        &self.location
    }
}

impl<E: fmt::Display> fmt::Display for ErrorWithLocation<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self.location() {
            Location::Unspecified => write!(f, "{}", self.error()),
            _ => write!(f, "{}: {}", self.location(), self.error()),
        }
    }
}

impl<E: error::Error> error::Error for ErrorWithLocation<E> {
    fn description(&self) -> &str {
        self.error.description()
    }

    fn cause(&self) -> Option<&error::Error> {
        Some(self.error())
    }
}

impl<E> From<E> for ErrorWithLocation<E> {
    fn from(e: E) -> ErrorWithLocation<E> {
        ErrorWithLocation::from_error(e)
    }
}

#[derive(Debug)]
pub enum CheckError {
    NotASchema,
    SchemaNotAFile,
    InvalidCsvxFilename,
    SchemaLoadError(SchemaLoadError),
    SchemaPathInvalid,
    SchemaPathUtf8Error,
}

impl From<SchemaLoadError> for CheckError {
    fn from(e: SchemaLoadError) -> CheckError {
        CheckError::SchemaLoadError(e)
    }
}

impl fmt::Display for CheckError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(cause) = self.cause() {
            write!(f, "{}", cause)
        } else {
            write!(f, "{}", self.description())
        }
    }
}

impl error::Error for CheckError {
    fn description(&self) -> &str {
        match *self {
            _ => "FIXME",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            _ => None,
        }
    }
}

#[derive(Clone, Debug)]
pub enum ColumnConstraintsError {
    MalformedConstraint,
    UnknownConstraint(String),
}

#[derive(Clone, Debug)]
pub enum ColumnTypeError {
    UnknownType,
}

#[derive(Debug)]
pub enum SchemaLoadError {
    Csv(csv::Error),
    MissingHeader,
    BadHeader,
    BadIdentifier(usize, String),
    BadType(usize, ColumnTypeError),
    BadConstraints(usize, ColumnConstraintsError),
}

impl From<csv::Error> for SchemaLoadError {
    fn from(e: csv::Error) -> SchemaLoadError {
        SchemaLoadError::Csv(e)
    }
}

#[derive(Debug)]
pub enum ValidationError {
    Csv(csv::Error),
    MissingHeaders,
    HeaderMismatch(usize, String),
    RowLengthMismatch(usize),
    ValueError(usize, usize, ValueError),
}

#[derive(Debug)]
pub enum ValueError {
    NonNullable,
    InvalidBool,
    InvalidInt,
    InvalidEnum,
    InvalidDecimal,
    InvalidDate,
    InvalidDateTime,
    InvalidTime,
}
<commit_msg>Added Helpful trait and help for CheckError.<commit_after>use csv;
use std::{cmp, error, fmt};
use std::error::Error;
use term_painter::{Attr, Color, ToStyle};
use term_size;
use textwrap;

pub trait Helpful {
    fn help(&self) -> String;
}

#[derive(Clone, Debug)]
pub enum Location {
    FileLineColumn(String, usize, usize),
    FileRowField(String, usize, usize),
    FileLine(String, usize),
    File(String),
    Unspecified,
}

impl fmt::Display for Location {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Location::FileLineColumn(ref file, line, col) => write!(f, "{}:{}:{}", file, line, col),
            Location::FileRowField(ref file, row, field) => {
                write!(f, "{}:{}[{}]", file, row, field)
            }
            Location::FileLine(ref file, line) => write!(f, "{}:{}]", file, line),
            Location::File(ref file) => write!(f, "{}", file),
            Location::Unspecified => Ok(()),
        }
    }
}

#[derive(Debug)]
pub struct ErrorWithLocation<E> {
    location: Location,
    error: E,
}

impl<E> ErrorWithLocation<E> {
    pub fn new<F: Into<E>>(location: Location, error: F) -> ErrorWithLocation<E> {
        ErrorWithLocation {
            location: location,
            error: error.into(),
        }
    }

    pub fn from_error<F: Into<E>>(other: F) -> ErrorWithLocation<E> {
        ErrorWithLocation::new(Location::Unspecified, other.into())
    }
}

impl<E: fmt::Display + Helpful> ErrorWithLocation<E> {
    pub fn print_help(&self) {
        println!("{}{} {}",
                 Attr::Bold.paint((Color::Red.paint("error"))),
                 Attr::Bold.paint(":"),
                 Attr::Bold.paint(self.error()));
        match *self.location() {
            Location::Unspecified => (),
            _ => println!("  --> {}", Color::Yellow.paint(self.location())),
        }

        let dims = term_size::dimensions().unwrap_or((80, 25));

        let term_width = cmp::max(dims.0, 4);
        let out = textwrap::wrap(self.error.help().as_str(), term_width - 3)
            .into_iter()
            .map(|line| textwrap::indent(line.as_str(), "   "))
            .fold(String::new(), |s1, s2| s1 + s2.as_str());
        println!("{}", out);
    }
}

impl<E> ErrorWithLocation<E> {
    pub fn error(&self) -> &E {
        &self.error
    }

    pub fn into_error(self) -> E {
        self.error
    }

    pub fn location(&self) -> &Location {
        &self.location
    }
}

impl<E: fmt::Display> fmt::Display for ErrorWithLocation<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self.location() {
            Location::Unspecified => write!(f, "{}", self.error()),
            _ => write!(f, "{}: {}", self.location(), self.error()),
        }
    }
}

impl<E: error::Error> error::Error for ErrorWithLocation<E> {
    fn description(&self) -> &str {
        self.error.description()
    }

    fn cause(&self) -> Option<&error::Error> {
        Some(self.error())
    }
}

impl<E> From<E> for ErrorWithLocation<E> {
    fn from(e: E) -> ErrorWithLocation<E> {
        ErrorWithLocation::from_error(e)
    }
}

#[derive(Debug)]
pub enum CheckError {
    NotASchema,
    SchemaNotAFile,
    InvalidCsvxFilename,
    SchemaLoadError(SchemaLoadError),
    SchemaPathUtf8Error,
}

impl From<SchemaLoadError> for CheckError {
    fn from(e: SchemaLoadError) -> CheckError {
        CheckError::SchemaLoadError(e)
    }
}

impl fmt::Display for CheckError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(cause) = self.cause() {
            write!(f, "{}", cause)
        } else {
            write!(f, "{}", self.description())
        }
    }
}

impl error::Error for CheckError {
    fn description(&self) -> &str {
        match *self {
            CheckError::NotASchema => "not a schema",
            CheckError::SchemaNotAFile => "schema is not a file",
            CheckError::InvalidCsvxFilename => "filename is not a valid CSVX filename",
            CheckError::SchemaLoadError(_) => "could not load schema",
            CheckError::SchemaPathUtf8Error => "filename UTF8 decoding error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            CheckError::SchemaLoadError(ref e) => Some(e),
            _ => None,
        }
    }
}

impl Helpful for CheckError {
    fn help(&self) -> String {
        match *self {
            CheckError::NotASchema => {
                "The file you provided is not a schema. The third field of \
                the filename must be of the form `csvx-schema-` followed by \
                the version number. As an example, when defining a schema \
                named `animals-2`, with a date of Dec 31st, 2015 and CSVX \
                version 5, the resulting filename should be: \
                `animals-2_20151231_csvx-schema-5.csv`. \n\
                Note that filenames are case sensitive!"
                        .to_owned()
            }
            CheckError::SchemaNotAFile => "The schema you supplied is not a valid file".to_owned(),
            CheckError::InvalidCsvxFilename => {
                "The filename provided is not in a valid CSVX form. CSVX \
                filenames have three components: The table name, date and \
                schema name. All components must be lowercase letters, \
                numbers or hyphens and start with a letter.\n\n\
                The table name component identifies the file or rather the \
                table it was exported from.\n\
                The date component is for the date the file was exported on.\n\
                The schema name component indicates which schema should be \
                used to validate its contents.\n\n\
                Example: With a table name of `nyc-zoo`, a date of Dec 31st, \
                2015 and using a schema named `animals-2`, the resulting \
                filename should be `nyc-zoo_20151231_animals-2.csv`."
                        .to_owned()
            }
            CheckError::SchemaPathUtf8Error => {
                "The filename you supplied contained UTF-8 errors. CSVX \
                filenames should only contain ASCII characters, please rename \
                the file and try again."
                        .to_owned()
            }
            CheckError::SchemaLoadError(ref e) => e.help(),
        }
    }
}

#[derive(Clone, Debug)]
pub enum ColumnConstraintsError {
    MalformedConstraint,
    UnknownConstraint(String),
}

#[derive(Clone, Debug)]
pub enum ColumnTypeError {
    UnknownType,
}

#[derive(Debug)]
pub enum SchemaLoadError {
    Csv(csv::Error),
    MissingHeader,
    BadHeader,
    BadIdentifier(usize, String),
    BadType(usize, ColumnTypeError),
    BadConstraints(usize, ColumnConstraintsError),
}

impl fmt::Display for SchemaLoadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(cause) = self.cause() {
            write!(f, "{}", cause)
        } else {
            write!(f, "{}", self.description())
        }
    }
}

impl error::Error for SchemaLoadError {
    fn description(&self) -> &str {
        match *self {
            _ => "TBW",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            _ => None,
        }
    }
}

impl Helpful for SchemaLoadError {
    fn help(&self) -> String {
        "FIXME".to_owned()
    }
}

impl From<csv::Error> for SchemaLoadError {
    fn from(e: csv::Error) -> SchemaLoadError {
        SchemaLoadError::Csv(e)
    }
}

#[derive(Debug)]
pub enum ValidationError {
    Csv(csv::Error),
    MissingHeaders,
    HeaderMismatch(usize, String),
    RowLengthMismatch(usize),
    ValueError(usize, usize, ValueError),
}

#[derive(Debug)]
pub enum ValueError {
    NonNullable,
    InvalidBool,
    InvalidInt,
    InvalidEnum,
    InvalidDecimal,
    InvalidDate,
    InvalidDateTime,
    InvalidTime,
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc.
//
// 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 libc::{c_char, c_int, int32_t, uint32_t, size_t};

pub enum ShadercCompiler {}
pub enum ShadercCompileOptions {}
pub enum ShadercCompilationResult {}

#[link(name = "shaderc_combined")]
#[link(name = "c++")]
extern "C" {
    pub fn shaderc_compiler_initialize() -> *mut ShadercCompiler;
    pub fn shaderc_compiler_release(compiler: *mut ShadercCompiler);

    pub fn shaderc_compile_into_spv(compiler: *const ShadercCompiler,
                                    source_text: *const c_char,
                                    source_size: size_t,
                                    shader_kind: int32_t,
                                    input_file_name: *const c_char,
                                    entry_point_name: *const c_char,
                                    additional_options: *const ShadercCompileOptions)
                                    -> *mut ShadercCompilationResult;
    pub fn shaderc_compile_into_spv_assembly(compiler: *const ShadercCompiler,
                                             source_text: *const c_char,
                                             source_size: size_t,
                                             shader_kind: int32_t,
                                             input_file_name: *const c_char,
                                             entry_point_name: *const c_char,
                                             additional_options: *const ShadercCompileOptions)
                                             -> *mut ShadercCompilationResult;
    pub fn shaderc_compile_into_preprocessed_text(compiler: *const ShadercCompiler,
                                                  source_text: *const c_char,
                                                  source_size: size_t,
                                                  shader_kind: int32_t,
                                                  input_file_name: *const c_char,
                                                  entry_point_name: *const c_char,
                                                  additional_options: *const ShadercCompileOptions)
                                                  -> *mut ShadercCompilationResult;
    pub fn shaderc_assemble_into_spv(compiler: *const ShadercCompiler,
                                     source_assembly: *const c_char,
                                     source_size: size_t,
                                     additional_options: *const ShadercCompileOptions)
                                     -> *mut ShadercCompilationResult;

    pub fn shaderc_compile_options_initialize() -> *mut ShadercCompileOptions;
    pub fn shaderc_compile_options_clone(options: *const ShadercCompileOptions)
                                         -> *mut ShadercCompileOptions;
    pub fn shaderc_compile_options_release(options: *mut ShadercCompileOptions);

    pub fn shaderc_compile_options_add_macro_definition(options: *mut ShadercCompileOptions,
                                                        name: *const c_char,
                                                        name_length: size_t,
                                                        value: *const c_char,
                                                        vaule_length: size_t);
    pub fn shaderc_compile_options_set_source_language(options: *mut ShadercCompileOptions,
                                                       language: int32_t);
    pub fn shaderc_compile_options_set_generate_debug_info(options: *mut ShadercCompileOptions);
    pub fn shaderc_compile_options_set_optimization_level(options: *mut ShadercCompileOptions,
                                                          level: int32_t);
    pub fn shaderc_compile_options_set_forced_version_profile(options: *mut ShadercCompileOptions,
                                                              version: c_int,
                                                              profile: int32_t);
    pub fn shaderc_compile_options_set_suppress_warnings(options: *mut ShadercCompileOptions);
    pub fn shaderc_compile_options_set_warnings_as_errors(options: *mut ShadercCompileOptions);
    pub fn shaderc_compile_options_set_target_env(options: *mut ShadercCompileOptions,
                                                  env: int32_t,
                                                  version: uint32_t);
    pub fn shaderc_compile_options_set_limit(options: *mut ShadercCompileOptions,
                                             limit: int32_t,
                                             value: c_int);

    pub fn shaderc_result_release(result: *mut ShadercCompilationResult);
    pub fn shaderc_result_get_compilation_status(result: *const ShadercCompilationResult) -> int32_t;
    pub fn shaderc_result_get_num_errors(result: *const ShadercCompilationResult) -> size_t;
    pub fn shaderc_result_get_num_warnings(result: *const ShadercCompilationResult) -> size_t;
    pub fn shaderc_result_get_error_message(result: *const ShadercCompilationResult) -> *const c_char;
    pub fn shaderc_result_get_length(result: *const ShadercCompilationResult) -> size_t;
    pub fn shaderc_result_get_bytes(result: *const ShadercCompilationResult) -> *const c_char;

    pub fn shaderc_get_spv_version(version: *mut c_int, revision: *mut c_int);
    pub fn shaderc_parse_version_profile(str: *const c_char,
                                         version: *mut c_int,
                                         profile: *mut int32_t)
                                         -> bool;
}
<commit_msg>Link to stdc++ instead of C++.<commit_after>// Copyright 2016 Google Inc.
//
// 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 libc::{c_char, c_int, int32_t, uint32_t, size_t};

pub enum ShadercCompiler {}
pub enum ShadercCompileOptions {}
pub enum ShadercCompilationResult {}

#[link(name = "shaderc_combined")]
#[link(name = "stdc++")]
extern "C" {
    pub fn shaderc_compiler_initialize() -> *mut ShadercCompiler;
    pub fn shaderc_compiler_release(compiler: *mut ShadercCompiler);

    pub fn shaderc_compile_into_spv(compiler: *const ShadercCompiler,
                                    source_text: *const c_char,
                                    source_size: size_t,
                                    shader_kind: int32_t,
                                    input_file_name: *const c_char,
                                    entry_point_name: *const c_char,
                                    additional_options: *const ShadercCompileOptions)
                                    -> *mut ShadercCompilationResult;
    pub fn shaderc_compile_into_spv_assembly(compiler: *const ShadercCompiler,
                                             source_text: *const c_char,
                                             source_size: size_t,
                                             shader_kind: int32_t,
                                             input_file_name: *const c_char,
                                             entry_point_name: *const c_char,
                                             additional_options: *const ShadercCompileOptions)
                                             -> *mut ShadercCompilationResult;
    pub fn shaderc_compile_into_preprocessed_text(compiler: *const ShadercCompiler,
                                                  source_text: *const c_char,
                                                  source_size: size_t,
                                                  shader_kind: int32_t,
                                                  input_file_name: *const c_char,
                                                  entry_point_name: *const c_char,
                                                  additional_options: *const ShadercCompileOptions)
                                                  -> *mut ShadercCompilationResult;
    pub fn shaderc_assemble_into_spv(compiler: *const ShadercCompiler,
                                     source_assembly: *const c_char,
                                     source_size: size_t,
                                     additional_options: *const ShadercCompileOptions)
                                     -> *mut ShadercCompilationResult;

    pub fn shaderc_compile_options_initialize() -> *mut ShadercCompileOptions;
    pub fn shaderc_compile_options_clone(options: *const ShadercCompileOptions)
                                         -> *mut ShadercCompileOptions;
    pub fn shaderc_compile_options_release(options: *mut ShadercCompileOptions);

    pub fn shaderc_compile_options_add_macro_definition(options: *mut ShadercCompileOptions,
                                                        name: *const c_char,
                                                        name_length: size_t,
                                                        value: *const c_char,
                                                        vaule_length: size_t);
    pub fn shaderc_compile_options_set_source_language(options: *mut ShadercCompileOptions,
                                                       language: int32_t);
    pub fn shaderc_compile_options_set_generate_debug_info(options: *mut ShadercCompileOptions);
    pub fn shaderc_compile_options_set_optimization_level(options: *mut ShadercCompileOptions,
                                                          level: int32_t);
    pub fn shaderc_compile_options_set_forced_version_profile(options: *mut ShadercCompileOptions,
                                                              version: c_int,
                                                              profile: int32_t);
    pub fn shaderc_compile_options_set_suppress_warnings(options: *mut ShadercCompileOptions);
    pub fn shaderc_compile_options_set_warnings_as_errors(options: *mut ShadercCompileOptions);
    pub fn shaderc_compile_options_set_target_env(options: *mut ShadercCompileOptions,
                                                  env: int32_t,
                                                  version: uint32_t);
    pub fn shaderc_compile_options_set_limit(options: *mut ShadercCompileOptions,
                                             limit: int32_t,
                                             value: c_int);

    pub fn shaderc_result_release(result: *mut ShadercCompilationResult);
    pub fn shaderc_result_get_compilation_status(result: *const ShadercCompilationResult) -> int32_t;
    pub fn shaderc_result_get_num_errors(result: *const ShadercCompilationResult) -> size_t;
    pub fn shaderc_result_get_num_warnings(result: *const ShadercCompilationResult) -> size_t;
    pub fn shaderc_result_get_error_message(result: *const ShadercCompilationResult) -> *const c_char;
    pub fn shaderc_result_get_length(result: *const ShadercCompilationResult) -> size_t;
    pub fn shaderc_result_get_bytes(result: *const ShadercCompilationResult) -> *const c_char;

    pub fn shaderc_get_spv_version(version: *mut c_int, revision: *mut c_int);
    pub fn shaderc_parse_version_profile(str: *const c_char,
                                         version: *mut c_int,
                                         profile: *mut int32_t)
                                         -> bool;
}
<|endoftext|>


<commit_before>use std::{mem, ptr};
use libc::{self, c_char};
use std::slice;
use std::cell::RefCell;
use std::collections::VecMap;

use super::get_ladspa_descriptor;

// essentially ladspa.h API translated to rust.
mod ladspa {
    use libc::{c_void, c_char};

    pub type Data = f32;
    pub type Properties = i32;
    pub type PortDescriptor = i32;
    pub type PortRangeHintDescriptor = i32;

    pub type Handle = *mut c_void;

    #[repr(C)]
    #[derive(Copy)]
    pub struct PortRangeHint {
        pub hint_descriptor: PortRangeHintDescriptor,
        pub lower_bound: Data,
        pub upper_bound: Data,
    }

    #[repr(C)]
    #[allow(missing_copy_implementations)] // Remove this for a fun warning/suggestion cycle!
    pub struct Descriptor {
        pub unique_id: u64,
        pub label: *const c_char,
        pub properties: Properties,
        pub name: *const c_char,
        pub maker: *const c_char,
        pub copyright: *const c_char,
        pub port_count: u64,
        pub port_descriptors: *mut PortDescriptor,
        pub port_names: *mut *const c_char,
        pub port_range_hints: *mut PortRangeHint,
        pub implementation_data: *mut c_void,
        pub instantiate: extern "C" fn(descriptor: *const Descriptor, sample_rate: u64) -> Handle,
        pub connect_port: extern "C" fn(instance: Handle, port: usize, data_location: *mut Data),
        pub activate: extern "C" fn(instance: Handle),
        pub run: extern "C" fn(instance: Handle, sample_count: u64),
        pub run_adding: extern "C" fn(instance: Handle, sample_count: u64),
        pub set_run_adding_gain: extern "C" fn(instance: Handle, gain: Data),
        pub deactivate: extern "C" fn(instance: Handle),
        pub cleanup: extern "C" fn(instance: Handle),
    }
}

// The handle that is given to ladspa.
struct Handle<'a> {
    descriptor: &'static super::PluginDescriptor,
    plugin: Box<super::Plugin + 'static>,
    ports: VecMap<super::PortConnection<'a>>,
}

unsafe fn alloc<T>(num: u64) -> *mut T {
    let ptr: *mut T = mem::transmute(libc::malloc(num * mem::size_of::<T>() as u64));
    if ptr == ptr::null_mut() {
        panic!("malloc returned null!");
    }
    ptr
}

unsafe fn free<T>(x: *const T) {
    libc::free(mem::transmute(x));
}

unsafe fn make_c_str(s: &'static str) -> *const c_char {
    let c_str: *mut c_char = alloc::<c_char>(s.len() as u64 + 1);
    ptr::copy_memory(c_str, mem::transmute(s.as_ptr()), s.len());
    slice::from_raw_parts_mut(c_str, s.len() + 1)[s.len()] = 0; // add the null terminator
    c_str
}

static mut init_done: bool = false;
static mut num_descriptors: u64 = 0;
static mut descriptors: Option<*mut *mut ladspa::Descriptor> = None;
static MAX_DESCRIPTORS: u64 = 32;

// It seems that ladspa_descriptor is deleted during link time optimization unless we
// call it from somewhere.
#[allow(dead_code)]
unsafe fn _lto_workaround() {
    ladspa_descriptor(0);
}

#[no_mangle]
/// This is exported so that your plugin is recognised by LADSPA hosts. Don't worry about it.
pub unsafe extern "C" fn ladspa_descriptor(index: u64) -> *mut ladspa::Descriptor {
    if !init_done {
        libc::atexit(global_destruct);
        descriptors = Some(alloc(MAX_DESCRIPTORS));
        init_done = true;
    }

    // If it's already been generated, return the cached copy.
    if index < num_descriptors {
        return *descriptors.unwrap().offset(index as isize);
    }

    match get_ladspa_descriptor(index) {
        Some(plugin) => {
            let desc: &mut ladspa::Descriptor = mem::transmute(alloc::<ladspa::Descriptor>(1));

            // the following is ok because none of the fields in the descriptor have
            // destructors. if they did rust would try to drop null pointers on write.

            // copy data fields
            desc.unique_id = plugin.unique_id;
            desc.label = make_c_str(plugin.label);
            desc.properties = plugin.properties.bits();
            desc.name = make_c_str(plugin.name);
            desc.maker = make_c_str(plugin.maker);
            desc.copyright = make_c_str(plugin.copyright);
            desc.port_count = plugin.ports.len() as u64;
            desc.port_descriptors = alloc::<ladspa::PortDescriptor>(desc.port_count);
            desc.port_names = alloc::<*const c_char>(desc.port_count);
            desc.port_range_hints = alloc::<ladspa::PortRangeHint>(desc.port_count);
            for i in 0..desc.port_count as usize {
                *desc.port_descriptors.offset(i as isize)
                    = plugin.ports[i].desc as i32;

                *desc.port_names.offset(i as isize)
                    = make_c_str(plugin.ports[i].name);

                let port = &plugin.ports[i];
                *desc.port_range_hints.offset(i as isize)
                    = ladspa::PortRangeHint {
                        hint_descriptor: port.hint.map(|x| x.bits()).unwrap_or(0) |
                            port.default.map(|x| x as i32).unwrap_or(0) |
                            port.lower_bound.map(|_| 1).unwrap_or(0) |
                            port.upper_bound.map(|_| 2).unwrap_or(0),
                        lower_bound: port.lower_bound.unwrap_or(0_f32),
                        upper_bound: port.upper_bound.unwrap_or(0_f32),
                    };
            }

            // implementation_data holds the original rustic descriptor
            desc.implementation_data = mem::transmute(alloc::<super::PluginDescriptor>(1));
            ptr::write(mem::transmute::<_, *mut super::PluginDescriptor>
                    (desc.implementation_data), plugin);

            // attach functions
            desc.instantiate = instantiate;
            desc.connect_port = connect_port;
            desc.run = run;
            desc.cleanup = cleanup;
            //desc.run_adding = run_adding;
            //desc.set_run_adding_gain = set_run_adding_gain;
            desc.activate = activate;
            desc.deactivate = deactivate;

            // store in global descriptor table
            let ptr = mem::transmute(desc);
            *descriptors.unwrap().offset(num_descriptors as isize) = ptr;
            num_descriptors += 1;
            if num_descriptors >= MAX_DESCRIPTORS {
                panic!("The program tried to define more than the max supported number of descriptors currently supported - this usually means you forgot to return None at some point in get_ladspa_descriptor.");
            }

            ptr
        }
        None => ptr::null_mut()
    }
}

// these next two should free everything allocated in ladspa_descriptor - checked with valgrind.
extern "C" fn global_destruct() {
    unsafe {
        if !init_done {
            return;
        }
        for i in 0..num_descriptors {
            free_descriptor(*descriptors.unwrap().offset(i as isize));
        }
        free(descriptors.unwrap());
    }
}

unsafe fn free_descriptor(ptr: *mut ladspa::Descriptor) {
    let desc: &mut ladspa::Descriptor = mem::transmute(ptr);
    free(desc.label);
    free(desc.name);
    free(desc.maker);
    free(desc.copyright);
    free(desc.port_descriptors);
    for i in 0..desc.port_count {
        free(*desc.port_names.offset(i as isize));
    }
    free(desc.port_names);
    free(desc.port_range_hints);
    let rust_desc: *mut super::PluginDescriptor = mem::transmute(desc.implementation_data);
    drop(ptr::read(rust_desc));
    free(desc.implementation_data);
    free(ptr);
}

extern "C" fn instantiate(descriptor: *const ladspa::Descriptor, sample_rate: u64) -> ladspa::Handle {
    unsafe {
        let desc: &mut ladspa::Descriptor = mem::transmute(descriptor);

        let rust_desc: &super::PluginDescriptor = mem::transmute(desc.implementation_data);
        let rust_plugin = (rust_desc.new)(rust_desc, sample_rate);
        let ports: Vec<super::PortConnection> = Vec::new();

        let heap_handle: *mut Handle = alloc::<Handle>(1);
        ptr::write(mem::transmute(&(*heap_handle).descriptor), rust_desc);
        ptr::write(mem::transmute(&(*heap_handle).plugin), rust_plugin);
        ptr::write(mem::transmute(&(*heap_handle).ports), ports);
        mem::transmute(heap_handle)
    }
}

extern "C" fn connect_port(instance: ladspa::Handle, port_num: usize, data_location: *mut ladspa::Data) {
    unsafe {
        let handle: &mut Handle = mem::transmute(instance);

        let port = handle.descriptor.ports[port_num];

        // Create appropriate pointers to port data. Mutable locations are wrapped in refcells.
        let data = match port.desc {
            super::PortDescriptor::AudioInput => {
                super::PortData::AudioInput( // Initially create a size 0 slice because we don't know how big
                    slice::from_raw_parts(mem::transmute(data_location), 0)) // it will be yet.
            },
            super::PortDescriptor::AudioOutput => {
                super::PortData::AudioOutput(RefCell::new( // Same here.
                    slice::from_raw_parts_mut(mem::transmute(data_location), 0)))
            },
            super::PortDescriptor::ControlInput => {
                super::PortData::ControlInput(mem::transmute(data_location))
            },
            super::PortDescriptor::ControlOutput => {
                super::PortData::ControlOutput(RefCell::new(mem::transmute(data_location)))
            },
        };

        let conn = super::PortConnection {
            port: port,
            data: data,
        };
        handle.ports.insert(port_num, conn);
    }
}

extern "C" fn run(instance: ladspa::Handle, sample_count: u64) {
    unsafe {
        let handle: *mut Handle = mem::transmute(instance);
        for (_, port) in (*handle).ports.iter_mut() {
            match port.data {
                super::PortData::AudioOutput(ref mut data) => {
                    let ptr = mem::transmute(data.borrow().as_ptr());
                    *data.borrow_mut() = slice::from_raw_parts_mut(ptr, sample_count as usize);
                },
                super::PortData::AudioInput(ref mut data) => {
                    let ptr = mem::transmute(data.as_ptr());
                    *data = slice::from_raw_parts(ptr, sample_count as usize);
                },
                _ => { }
            }
        }
        let ports: Vec<&super::PortConnection> =
            (0..(*handle).ports.len()).map(|i| &(*handle).ports[i]).collect();
        (*handle).plugin.run(sample_count as usize, ports.as_slice());
    }
}

extern "C" fn activate(instance: ladspa::Handle) {
    unsafe{
        let handle: &mut Handle = mem::transmute(instance);
        handle.plugin.activate();
    }
}
extern "C" fn deactivate(instance: ladspa::Handle) {
    unsafe {
        let handle: &mut Handle = mem::transmute(instance);
        handle.plugin.deactivate();
    }
}

/*
extern "C" fn run_adding(instance: ladspa::Handle, sample_count: u64) {
}
extern "C" fn set_run_adding_gain(instance: ladspa::Handle, gain: ladspa::Data) {
}
*/

extern "C" fn cleanup(instance: ladspa::Handle) {
    unsafe {
        let handle: *mut Handle = mem::transmute(instance);
        drop(ptr::read(handle));
        free(instance);
    }
}

<commit_msg>Reduce overhead by moving some processing from run() to connect_port()<commit_after>use std::{mem, ptr};
use libc::{self, c_char};
use std::slice;
use std::cell::RefCell;
use std::collections::VecMap;

use super::get_ladspa_descriptor;

// essentially ladspa.h API translated to rust.
mod ladspa {
    use libc::{c_void, c_char};

    pub type Data = f32;
    pub type Properties = i32;
    pub type PortDescriptor = i32;
    pub type PortRangeHintDescriptor = i32;

    pub type Handle = *mut c_void;

    #[repr(C)]
    #[derive(Copy)]
    pub struct PortRangeHint {
        pub hint_descriptor: PortRangeHintDescriptor,
        pub lower_bound: Data,
        pub upper_bound: Data,
    }

    #[repr(C)]
    #[allow(missing_copy_implementations)] // Remove this for a fun warning/suggestion cycle!
    pub struct Descriptor {
        pub unique_id: u64,
        pub label: *const c_char,
        pub properties: Properties,
        pub name: *const c_char,
        pub maker: *const c_char,
        pub copyright: *const c_char,
        pub port_count: u64,
        pub port_descriptors: *mut PortDescriptor,
        pub port_names: *mut *const c_char,
        pub port_range_hints: *mut PortRangeHint,
        pub implementation_data: *mut c_void,
        pub instantiate: extern "C" fn(descriptor: *const Descriptor, sample_rate: u64) -> Handle,
        pub connect_port: extern "C" fn(instance: Handle, port: usize, data_location: *mut Data),
        pub activate: extern "C" fn(instance: Handle),
        pub run: extern "C" fn(instance: Handle, sample_count: u64),
        pub run_adding: extern "C" fn(instance: Handle, sample_count: u64),
        pub set_run_adding_gain: extern "C" fn(instance: Handle, gain: Data),
        pub deactivate: extern "C" fn(instance: Handle),
        pub cleanup: extern "C" fn(instance: Handle),
    }
}

unsafe fn alloc<T>(num: u64) -> *mut T {
    let ptr: *mut T = mem::transmute(libc::malloc(num * mem::size_of::<T>() as u64));
    if ptr == ptr::null_mut() {
        panic!("malloc returned null!");
    }
    ptr
}

unsafe fn free<T>(x: *const T) {
    libc::free(mem::transmute(x));
}

unsafe fn make_c_str(s: &'static str) -> *const c_char {
    let c_str: *mut c_char = alloc::<c_char>(s.len() as u64 + 1);
    ptr::copy_memory(c_str, mem::transmute(s.as_ptr()), s.len());
    slice::from_raw_parts_mut(c_str, s.len() + 1)[s.len()] = 0; // add the null terminator
    c_str
}

static mut init_done: bool = false;
static mut num_descriptors: u64 = 0;
static mut descriptors: Option<*mut *mut ladspa::Descriptor> = None;
static MAX_DESCRIPTORS: u64 = 32;

// It seems that ladspa_descriptor is deleted during link time optimization unless we
// call it from somewhere.
#[allow(dead_code)]
unsafe fn _lto_workaround() {
    ladspa_descriptor(0);
}

#[no_mangle]
/// This is exported so that your plugin is recognised by LADSPA hosts. Don't worry about it.
pub unsafe extern "C" fn ladspa_descriptor(index: u64) -> *mut ladspa::Descriptor {
    if !init_done {
        libc::atexit(global_destruct);
        descriptors = Some(alloc(MAX_DESCRIPTORS));
        init_done = true;
    }

    // If it's already been generated, return the cached copy.
    if index < num_descriptors {
        return *descriptors.unwrap().offset(index as isize);
    }

    match get_ladspa_descriptor(index) {
        Some(plugin) => {
            let desc: &mut ladspa::Descriptor = mem::transmute(alloc::<ladspa::Descriptor>(1));

            // the following is ok because none of the fields in the descriptor have
            // destructors. if they did rust would try to drop null pointers on write.

            // copy data fields
            desc.unique_id = plugin.unique_id;
            desc.label = make_c_str(plugin.label);
            desc.properties = plugin.properties.bits();
            desc.name = make_c_str(plugin.name);
            desc.maker = make_c_str(plugin.maker);
            desc.copyright = make_c_str(plugin.copyright);
            desc.port_count = plugin.ports.len() as u64;
            desc.port_descriptors = alloc::<ladspa::PortDescriptor>(desc.port_count);
            desc.port_names = alloc::<*const c_char>(desc.port_count);
            desc.port_range_hints = alloc::<ladspa::PortRangeHint>(desc.port_count);
            for i in 0..desc.port_count as usize {
                *desc.port_descriptors.offset(i as isize)
                    = plugin.ports[i].desc as i32;

                *desc.port_names.offset(i as isize)
                    = make_c_str(plugin.ports[i].name);

                let port = &plugin.ports[i];
                *desc.port_range_hints.offset(i as isize)
                    = ladspa::PortRangeHint {
                        hint_descriptor: port.hint.map(|x| x.bits()).unwrap_or(0) |
                            port.default.map(|x| x as i32).unwrap_or(0) |
                            port.lower_bound.map(|_| 1).unwrap_or(0) |
                            port.upper_bound.map(|_| 2).unwrap_or(0),
                        lower_bound: port.lower_bound.unwrap_or(0_f32),
                        upper_bound: port.upper_bound.unwrap_or(0_f32),
                    };
            }

            // implementation_data holds the original rustic descriptor
            desc.implementation_data = mem::transmute(alloc::<super::PluginDescriptor>(1));
            ptr::write(mem::transmute::<_, *mut super::PluginDescriptor>
                    (desc.implementation_data), plugin);

            // attach functions
            desc.instantiate = instantiate;
            desc.connect_port = connect_port;
            desc.run = run;
            desc.cleanup = cleanup;
            //desc.run_adding = run_adding;
            //desc.set_run_adding_gain = set_run_adding_gain;
            desc.activate = activate;
            desc.deactivate = deactivate;

            // store in global descriptor table
            let ptr = mem::transmute(desc);
            *descriptors.unwrap().offset(num_descriptors as isize) = ptr;
            num_descriptors += 1;
            if num_descriptors >= MAX_DESCRIPTORS {
                panic!("The program tried to define more than the max supported number of descriptors currently supported - this usually means you forgot to return None at some point in get_ladspa_descriptor.");
            }

            ptr
        }
        None => ptr::null_mut()
    }
}

// these next two should free everything allocated in ladspa_descriptor - checked with valgrind.
extern "C" fn global_destruct() {
    unsafe {
        if !init_done {
            return;
        }
        for i in 0..num_descriptors {
            free_descriptor(*descriptors.unwrap().offset(i as isize));
        }
        free(descriptors.unwrap());
    }
}

unsafe fn free_descriptor(ptr: *mut ladspa::Descriptor) {
    let desc: &mut ladspa::Descriptor = mem::transmute(ptr);
    free(desc.label);
    free(desc.name);
    free(desc.maker);
    free(desc.copyright);
    free(desc.port_descriptors);
    for i in 0..desc.port_count {
        free(*desc.port_names.offset(i as isize));
    }
    free(desc.port_names);
    free(desc.port_range_hints);
    let rust_desc: *mut super::PluginDescriptor = mem::transmute(desc.implementation_data);
    drop(ptr::read(rust_desc));
    free(desc.implementation_data);
    free(ptr);
}

// The handle that is given to ladspa.
struct Handle<'a> {
    descriptor: &'static super::PluginDescriptor,
    plugin: Box<super::Plugin + 'static>,
    port_map: VecMap<super::PortConnection<'a>>,
    ports: Vec<&'a super::PortConnection<'a>>,
}

extern "C" fn instantiate(descriptor: *const ladspa::Descriptor, sample_rate: u64) -> ladspa::Handle {
    unsafe {
        let desc: &mut ladspa::Descriptor = mem::transmute(descriptor);

        let rust_desc: &super::PluginDescriptor = mem::transmute(desc.implementation_data);
        let rust_plugin = (rust_desc.new)(rust_desc, sample_rate);
        let port_map: VecMap<super::PortConnection> = VecMap::new();
        let ports: Vec<&super::PortConnection> = Vec::new();

        let heap_handle: *mut Handle = alloc::<Handle>(1);
        ptr::write(mem::transmute(&(*heap_handle).descriptor), rust_desc);
        ptr::write(mem::transmute(&(*heap_handle).plugin), rust_plugin);
        ptr::write(mem::transmute(&(*heap_handle).port_map), port_map);
        ptr::write(mem::transmute(&(*heap_handle).ports), ports);
        mem::transmute(heap_handle)
    }
}

extern "C" fn connect_port(instance: ladspa::Handle, port_num: usize, data_location: *mut ladspa::Data) {
    unsafe {
        let handle: &mut Handle = mem::transmute(instance);

        let port = handle.descriptor.ports[port_num];

        // Create appropriate pointers to port data. Mutable locations are wrapped in refcells.
        let data = match port.desc {
            super::PortDescriptor::AudioInput => {
                super::PortData::AudioInput( // Initially create a size 0 slice because we don't know how big
                    slice::from_raw_parts(mem::transmute(data_location), 0)) // it will be yet.
            },
            super::PortDescriptor::AudioOutput => {
                super::PortData::AudioOutput(RefCell::new( // Same here.
                    slice::from_raw_parts_mut(mem::transmute(data_location), 0)))
            },
            super::PortDescriptor::ControlInput => {
                super::PortData::ControlInput(mem::transmute(data_location))
            },
            super::PortDescriptor::ControlOutput => {
                super::PortData::ControlOutput(RefCell::new(mem::transmute(data_location)))
            },
        };

        let conn = super::PortConnection {
            port: port,
            data: data,
        };
        handle.port_map.insert(port_num, conn);

        // Depends on the assumption that ports will be recreated whenever port_map changes
        let handle_ptr: *mut Handle = mem::transmute(instance);
        if handle.port_map.len() == handle.descriptor.ports.len() {
            (*handle_ptr).ports = (0..handle.port_map.len()).map(|i| &handle.port_map[i]).collect();
        }
    }
}

extern "C" fn run(instance: ladspa::Handle, sample_count: u64) {
    unsafe {
        let handle: &mut Handle = mem::transmute(instance);
        for (_, port) in handle.port_map.iter_mut() {
            match port.data {
                super::PortData::AudioOutput(ref mut data) => {
                    let ptr = mem::transmute(data.borrow().as_ptr());
                    *data.borrow_mut() = slice::from_raw_parts_mut(ptr, sample_count as usize);
                },
                super::PortData::AudioInput(ref mut data) => {
                    let ptr = mem::transmute(data.as_ptr());
                    *data = slice::from_raw_parts(ptr, sample_count as usize);
                },
                _ => { }
            }
        }
        handle.plugin.run(sample_count as usize, handle.ports.as_slice());
    }
}

extern "C" fn activate(instance: ladspa::Handle) {
    unsafe{
        let handle: &mut Handle = mem::transmute(instance);
        handle.plugin.activate();
    }
}
extern "C" fn deactivate(instance: ladspa::Handle) {
    unsafe {
        let handle: &mut Handle = mem::transmute(instance);
        handle.plugin.deactivate();
    }
}

/*
extern "C" fn run_adding(instance: ladspa::Handle, sample_count: u64) {
}
extern "C" fn set_run_adding_gain(instance: ladspa::Handle, gain: ladspa::Data) {
}
*/

extern "C" fn cleanup(instance: ladspa::Handle) {
    unsafe {
        let handle: *mut Handle = mem::transmute(instance);
        drop(ptr::read(handle));
        free(instance);
    }
}

<|endoftext|>


<commit_before>// -*- flycheck-rust-crate-root: "lib.rs" -*-
use libc::{c_char, c_int, c_double, c_void, c_ushort};
use std::ptr;
use std::c_str::ToCStr;

#[repr(C)]
pub struct Document;
#[repr(C)]
pub struct Context;
#[allow(dead_code)]
#[repr(C)]
pub struct XPathObject {
    xpath_type: c_ushort,
    pub node_set: *const NodeSet,
    bool_val: c_int,
    float_val: c_double,
    string_val: *const c_char,
    user: *const c_void,
    index: c_int,
    user2: *const c_void,
    index2: c_int
}
/// The nodeset
#[allow(dead_code)]
#[repr(C)]
pub struct NodeSet {
    node_nr: c_int,
    node_max: c_int,
    node_tab: *mut Node
}

/// A node from the nodeset
#[allow(dead_code)]
#[repr(C)]
pub struct Node {
    private: *const c_void,
    element_type: c_ushort,
    name: *const c_char,
    children: *const Node,
    last: *const Node,
    parent: *const Node,
    next: *const Node,
    prev: *const Node,
    doc: *const Document,
    namespace: *const Namespace,
    content: *const c_char,
    properties: *const Attribute,
    namespace_def: *const Namespace,
    psvi: *const c_void,
    line: c_ushort,
    extra: c_ushort
}
#[repr(C)]
pub struct Namespace;
#[repr(C)]
pub struct Attribute;

#[link(name = "xml2")]
extern {
    pub fn xmlParseDoc(body: *const c_char) -> *const Document;
    pub fn xmlParseFile(filename: *const c_char) -> *const Document;
    pub fn xmlFreeDoc(doc: *const Document);

    pub fn xmlXPathNewContext(doc: *const Document) -> *const Context;
    pub fn xmlXPathFreeContext(context: *const Context);

    pub fn xmlXPathEvalExpression(xpath: *const c_char, context: *const Context)
                                  -> *const XPathObject;
    pub fn xmlXPathFreeObject(object: *const XPathObject);
}

#[inline]
fn xml_xpath_node_set_is_empty(ns: *const NodeSet) -> bool {
    unsafe {
        ns.is_null() || (*ns).node_nr==0 || (*ns).node_tab.is_null()
    }
}

impl XPathObject {
    pub fn from_context(context: *const Context,
                        xpath: &str) -> *const XPathObject
    {
        unsafe {
            let result = xmlXPathEvalExpression(xpath.to_c_str().as_ptr(),
                                                context);
            if result.is_null() {
                ptr::null()
            } else if xml_xpath_node_set_is_empty((*result).node_set) {
                xmlXPathFreeObject(result);
                ptr::null()
            } else {
                result
            }
        }
    }
}

impl<'a> NodeSet {
    /// Gets a vector of nodes from the NodeSet
    pub fn get_nodes(&'a self) -> Vec<&'a Node> {
        unsafe {
            let node_ptr = self.node_tab;
            if node_ptr.is_null() {
                vec![]
            } else {
                range(0, self.node_nr).map(
                    |off| &*self.node_tab.clone().offset(off as int)).collect()
            }
        }
    }
}
<commit_msg>Impl Copy for Node and NodeSet<commit_after>// -*- flycheck-rust-crate-root: "lib.rs" -*-
use libc::{c_char, c_int, c_double, c_void, c_ushort};
use std::ptr;
use std::c_str::ToCStr;

#[repr(C)]
pub struct Document;
#[repr(C)]
pub struct Context;
#[allow(dead_code)]
#[repr(C)]
pub struct XPathObject {
    xpath_type: c_ushort,
    pub node_set: *const NodeSet,
    bool_val: c_int,
    float_val: c_double,
    string_val: *const c_char,
    user: *const c_void,
    index: c_int,
    user2: *const c_void,
    index2: c_int
}
/// The nodeset
#[allow(dead_code)]
#[repr(C)]
pub struct NodeSet {
    node_nr: c_int,
    node_max: c_int,
    node_tab: *mut Node
}

/// A node from the nodeset
#[allow(dead_code)]
#[repr(C)]
pub struct Node {
    private: *const c_void,
    element_type: c_ushort,
    name: *const c_char,
    children: *const Node,
    last: *const Node,
    parent: *const Node,
    next: *const Node,
    prev: *const Node,
    doc: *const Document,
    namespace: *const Namespace,
    content: *const c_char,
    properties: *const Attribute,
    namespace_def: *const Namespace,
    psvi: *const c_void,
    line: c_ushort,
    extra: c_ushort
}
#[repr(C)]
pub struct Namespace;
#[repr(C)]
pub struct Attribute;

#[link(name = "xml2")]
extern {
    pub fn xmlParseDoc(body: *const c_char) -> *const Document;
    pub fn xmlParseFile(filename: *const c_char) -> *const Document;
    pub fn xmlFreeDoc(doc: *const Document);

    pub fn xmlXPathNewContext(doc: *const Document) -> *const Context;
    pub fn xmlXPathFreeContext(context: *const Context);

    pub fn xmlXPathEvalExpression(xpath: *const c_char, context: *const Context)
                                  -> *const XPathObject;
    pub fn xmlXPathFreeObject(object: *const XPathObject);
}

#[inline]
fn xml_xpath_node_set_is_empty(ns: *const NodeSet) -> bool {
    unsafe {
        ns.is_null() || (*ns).node_nr==0 || (*ns).node_tab.is_null()
    }
}

impl XPathObject {
    pub fn from_context(context: *const Context,
                        xpath: &str) -> *const XPathObject
    {
        unsafe {
            let result = xmlXPathEvalExpression(xpath.to_c_str().as_ptr(),
                                                context);
            if result.is_null() {
                ptr::null()
            } else if xml_xpath_node_set_is_empty((*result).node_set) {
                xmlXPathFreeObject(result);
                ptr::null()
            } else {
                result
            }
        }
    }
}

impl Copy for Node {}

impl Copy for NodeSet {}

impl<'a> NodeSet {
    /// Gets a vector of nodes from the NodeSet
    pub fn get_nodes(&'a self) -> Vec<&'a Node> {
        unsafe {
            let node_ptr = self.node_tab;
            if node_ptr.is_null() {
                vec![]
            } else {
                range(0, self.node_nr).map(
                    |off| &*self.node_tab.clone().offset(off as int)).collect()
            }
        }
    }
}
<|endoftext|>


<commit_before>//!  Decoding of GIF Images
//!
//!  GIF (Graphics Interchange Format) is an image format that supports lossless compression.
//!
//!  # Related Links
//!  * <http://www.w3.org/Graphics/GIF/spec-gif89a.txt> - The GIF Specification
//!
//! # Examples
//! ```rust,no_run
//! use image::gif::{GifDecoder, Encoder};
//! use image::{ImageDecoder, AnimationDecoder};
//! use std::fs::File;
//! # fn main() -> std::io::Result<()> {
//! // Decode a gif into frames
//! let file_in = File::open("foo.gif")?;
//! let mut decoder = GifDecoder::new(file_in).unwrap();
//! let frames = decoder.into_frames();
//! let frames = frames.collect_frames().expect("error decoding gif");
//!
//! // Encode frames into a gif and save to a file
//! let mut file_out = File::open("out.gif")?;
//! let mut encoder = Encoder::new(file_out);
//! encoder.encode_frames(frames.into_iter());
//! # Ok(())
//! # }
//! ```
#![allow(clippy::while_let_loop)]

extern crate gif;
extern crate num_rational;

use std::clone::Clone;
use std::cmp::min;
use std::convert::TryFrom;
use std::io::{self, Cursor, Read, Write};
use std::marker::PhantomData;
use std::mem;

use self::gif::{ColorOutput, SetParameter};
pub use self::gif::{DisposalMethod, Frame};

use animation;
use buffer::{ImageBuffer, Pixel};
use color::{self, Rgba};
use image::{self, AnimationDecoder, ImageDecoder, ImageError, ImageResult};
use num_rational::Ratio;

/// GIF decoder
pub struct GifDecoder<R: Read> {
    reader: gif::Reader<R>,
}

impl<R: Read> GifDecoder<R> {
    /// Creates a new decoder that decodes the input steam ```r```
    pub fn new(r: R) -> ImageResult<GifDecoder<R>> {
        let mut decoder = gif::Decoder::new(r);
        decoder.set(ColorOutput::RGBA);

        Ok(GifDecoder {
            reader: decoder.read_info()?,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct GifReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for GifReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for GifDecoder<R> {
    type Reader = GifReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        (u32::from(self.reader.width()), u32::from(self.reader.height()))
    }

    fn color_type(&self) -> color::ColorType {
        color::ColorType::Rgba8
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        Ok(GifReader(Cursor::new(image::decoder_to_vec(self)?), PhantomData))
    }

    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));

        let (f_width, f_height, left, top);

        if let Some(frame) = self.reader.next_frame_info()? {
            left = u32::from(frame.left);
            top = u32::from(frame.top);
            f_width = u32::from(frame.width);
            f_height = u32::from(frame.height);
        } else {
            return Err(ImageError::ImageEnd);
        }

        self.reader.read_into_buffer(buf)?;

        let (width, height) = (u32::from(self.reader.width()), u32::from(self.reader.height()));
        if (left, top) != (0, 0) || (width, height) != (f_width, f_height) {
            // TODO: Avoid unnecessary allocation here.

            // See the comments inside `<GifFrameIterator as Iterator>::next` about
            // the error handling of `from_raw`.
            let image = ImageBuffer::from_raw(f_width, f_height, &mut *buf).ok_or_else(
                || ImageError::UnsupportedError("Image dimensions are too large".into())
            )?;

            // Recover the full image
            let image_buffer = ImageBuffer::from_fn(width, height, |x, y| {
                let x = x.wrapping_sub(left);
                let y = y.wrapping_sub(top);
                if x < image.width() && y < image.height() {
                    *image.get_pixel(x, y)
                } else {
                    Rgba([0, 0, 0, 0])
                }
            });
            buf.copy_from_slice(&mut image_buffer.into_raw());
        }
        Ok(())
    }
}

struct GifFrameIterator<R: Read> {
    reader: gif::Reader<R>,

    width: u32,
    height: u32,

    non_disposed_frame: ImageBuffer<Rgba<u8>, Vec<u8>>,
}

impl<R: Read> GifFrameIterator<R> {
    fn new(decoder: GifDecoder<R>) -> GifFrameIterator<R> {
        let (width, height) = decoder.dimensions();

        // TODO: Avoid this cast
        let (width, height) = (width as u32, height as u32);

        // intentionally ignore the background color for web compatibility

        // create the first non disposed frame
        let non_disposed_frame = ImageBuffer::from_pixel(width, height, Rgba([0, 0, 0, 0]));

        GifFrameIterator {
            reader: decoder.reader,
            width,
            height,
            non_disposed_frame,
        }
    }
}

impl<R: Read> Iterator for GifFrameIterator<R> {
    type Item = ImageResult<animation::Frame>;

    fn next(&mut self) -> Option<ImageResult<animation::Frame>> {
        // begin looping over each frame
        let (left, top, delay, dispose, f_width, f_height);

        match self.reader.next_frame_info() {
            Ok(frame_info) => {
                if let Some(frame) = frame_info {
                    left = u32::from(frame.left);
                    top = u32::from(frame.top);
                    f_width = u32::from(frame.width);
                    f_height = u32::from(frame.height);

                    // frame.delay is in units of 10ms so frame.delay*10 is in ms
                    delay = Ratio::new(frame.delay * 10, 1);
                    dispose = frame.dispose;
                } else {
                    // no more frames
                    return None;
                }
            },
            Err(err) => return Some(Err(err.into())),
        }

        let mut vec = vec![0; self.reader.buffer_size()];
        if let Err(err) = self.reader.fill_buffer(&mut vec) {
            return Some(Err(err.into()));
        }

        // create the image buffer from the raw frame.
        // `buffer_size` uses wrapping arithmetics, thus might not report the
        // correct storage requirement if the result does not fit in `usize`.
        // on the other hand, `ImageBuffer::from_raw` detects overflow and
        // reports by returning `None`.
        let image_buffer_raw = match ImageBuffer::from_raw(f_width, f_height, vec) {
            Some(image_buffer_raw) => image_buffer_raw,
            None => {
                return Some(Err(ImageError::UnsupportedError(
                    "Image dimensions are too large".into(),
                )))
            }
        };

        // if `image_buffer_raw`'s frame exactly matches the entire image, then
        // use it directly.
        //
        // otherwise, `image_buffer_raw` represents a smaller image.
        // create a new image of the target size and place
        // `image_buffer_raw` within it. the outside region is filled with
        // transparent pixels.
        let mut image_buffer =
            full_image_from_frame(self.width, self.height, image_buffer_raw, left, top);

        // loop over all pixels, checking if any pixels from the non disposed
        // frame need to be used
        for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
            let previous_img_buffer = &self.non_disposed_frame;
            let adjusted_pixel: &mut Rgba<u8> = pixel;
            let previous_pixel: &Rgba<u8> = previous_img_buffer.get_pixel(x, y);

            let pixel_alpha = adjusted_pixel.channels()[3];

            // If a pixel is not visible then we show the non disposed frame pixel instead
            if pixel_alpha == 0 {
                adjusted_pixel.blend(previous_pixel);
            }
        }

        let frame = animation::Frame::from_parts(
            image_buffer.clone(), 0, 0, delay
        );

        match dispose {
            DisposalMethod::Any => {
                // do nothing
                // (completely replace this frame with the next)
            }
            DisposalMethod::Keep => {
                // do not dispose
                // (keep pixels from this frame)
                self.non_disposed_frame = image_buffer;
            }
            DisposalMethod::Background => {
                // restore to background color
                // (background shows through transparent pixels in the next frame)
                for y in top..min(top + f_height, self.height) {
                    for x in left..min(left + f_width, self.width) {
                        self.non_disposed_frame.put_pixel(x, y, Rgba([0, 0, 0, 0]));
                    }
                }
            }
            DisposalMethod::Previous => {
                // restore to previous
                // (dispose frames leaving the last none disposal frame)
            }
        };

        Some(Ok(frame))
    }
}

/// Given a frame subimage, construct a full image of size
/// `(screen_width, screen_height)` by placing it at the top-left coordinates
/// `(left, top)`. The remaining portion is filled with transparent pixels.
fn full_image_from_frame(
    screen_width: u32,
    screen_height: u32,
    image: crate::RgbaImage,
    left: u32,
    top: u32,
) -> crate::RgbaImage {
    if (left, top) == (0, 0) && (screen_width, screen_height) == (image.width(), image.height()) {
        image
    } else {
        ImageBuffer::from_fn(screen_width, screen_height, |x, y| {
            let x = x.wrapping_sub(left);
            let y = y.wrapping_sub(top);
            if x < image.width() && y < image.height() {
                *image.get_pixel(x, y)
            } else {
                Rgba([0, 0, 0, 0])
            }
        })
    }
}

impl<'a, R: Read + 'a> AnimationDecoder<'a> for GifDecoder<R> {
    fn into_frames(self) -> animation::Frames<'a> {
        animation::Frames::new(Box::new(GifFrameIterator::new(self)))
    }
}

/// GIF encoder.
pub struct Encoder<W: Write> {
    w: Option<W>,
    gif_encoder: Option<gif::Encoder<W>>,
}

impl<W: Write> Encoder<W> {
    /// Creates a new GIF encoder.
    pub fn new(w: W) -> Encoder<W> {
        Encoder {
            w: Some(w),
            gif_encoder: None,
        }
    }
    /// Encodes a frame.
    pub fn encode(&mut self, frame: &Frame) -> ImageResult<()> {
        let result;
        if let Some(ref mut encoder) = self.gif_encoder {
            result = encoder.write_frame(frame).map_err(|err| err.into());
        } else {
            let writer = self.w.take().unwrap();
            let mut encoder = gif::Encoder::new(writer, frame.width, frame.height, &[])?;
            result = encoder.write_frame(&frame).map_err(|err| err.into());
            self.gif_encoder = Some(encoder);
        }
        result
    }

    /// Encodes Frames.
    /// Consider using `try_encode_frames` instead to encode an `animation::Frames` like iterator.
    pub fn encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
    where
        F: IntoIterator<Item = animation::Frame>
    {
        for img_frame in frames {
            self.encode_single_frame(img_frame)?;
        }
        Ok(())
    }

    /// Try to encode a collection of `ImageResult<animation::Frame>` objects.
    /// Use this function to encode an `animation::Frames` like iterator.
    /// Whenever an `Err` item is encountered, that value is returned without further actions.
    pub fn try_encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
    where
        F: IntoIterator<Item = ImageResult<animation::Frame>>
    {
        for img_frame in frames {
            self.encode_single_frame(img_frame?)?;
        }
        Ok(())
    }

    fn encode_single_frame(&mut self, img_frame: animation::Frame) -> ImageResult<()> {
        // get the delay before converting img_frame
        let frame_delay = img_frame.delay().to_integer();
        // convert img_frame into RgbaImage
        let rbga_frame = img_frame.into_buffer();

        // Create the gif::Frame from the animation::Frame
        let mut frame = Frame::from_rgba(rbga_frame.width() as u16, rbga_frame.height() as u16, &mut rbga_frame.into_raw());
        frame.delay = frame_delay;

        // encode the gif::Frame
        self.encode(&frame)
    }
}

impl From<gif::DecodingError> for ImageError {
    fn from(err: gif::DecodingError) -> ImageError {
        use self::gif::DecodingError::*;
        match err {
            Format(desc) | Internal(desc) => ImageError::FormatError(desc.into()),
            Io(io_err) => ImageError::IoError(io_err),
        }
    }
}
<commit_msg>Add comment explaining GIF decoding better<commit_after>//!  Decoding of GIF Images
//!
//!  GIF (Graphics Interchange Format) is an image format that supports lossless compression.
//!
//!  # Related Links
//!  * <http://www.w3.org/Graphics/GIF/spec-gif89a.txt> - The GIF Specification
//!
//! # Examples
//! ```rust,no_run
//! use image::gif::{GifDecoder, Encoder};
//! use image::{ImageDecoder, AnimationDecoder};
//! use std::fs::File;
//! # fn main() -> std::io::Result<()> {
//! // Decode a gif into frames
//! let file_in = File::open("foo.gif")?;
//! let mut decoder = GifDecoder::new(file_in).unwrap();
//! let frames = decoder.into_frames();
//! let frames = frames.collect_frames().expect("error decoding gif");
//!
//! // Encode frames into a gif and save to a file
//! let mut file_out = File::open("out.gif")?;
//! let mut encoder = Encoder::new(file_out);
//! encoder.encode_frames(frames.into_iter());
//! # Ok(())
//! # }
//! ```
#![allow(clippy::while_let_loop)]

extern crate gif;
extern crate num_rational;

use std::clone::Clone;
use std::cmp::min;
use std::convert::TryFrom;
use std::io::{self, Cursor, Read, Write};
use std::marker::PhantomData;
use std::mem;

use self::gif::{ColorOutput, SetParameter};
pub use self::gif::{DisposalMethod, Frame};

use animation;
use buffer::{ImageBuffer, Pixel};
use color::{self, Rgba};
use image::{self, AnimationDecoder, ImageDecoder, ImageError, ImageResult};
use num_rational::Ratio;

/// GIF decoder
pub struct GifDecoder<R: Read> {
    reader: gif::Reader<R>,
}

impl<R: Read> GifDecoder<R> {
    /// Creates a new decoder that decodes the input steam ```r```
    pub fn new(r: R) -> ImageResult<GifDecoder<R>> {
        let mut decoder = gif::Decoder::new(r);
        decoder.set(ColorOutput::RGBA);

        Ok(GifDecoder {
            reader: decoder.read_info()?,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct GifReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for GifReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for GifDecoder<R> {
    type Reader = GifReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        (u32::from(self.reader.width()), u32::from(self.reader.height()))
    }

    fn color_type(&self) -> color::ColorType {
        color::ColorType::Rgba8
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        Ok(GifReader(Cursor::new(image::decoder_to_vec(self)?), PhantomData))
    }

    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));

        let (f_width, f_height, left, top);

        if let Some(frame) = self.reader.next_frame_info()? {
            left = u32::from(frame.left);
            top = u32::from(frame.top);
            f_width = u32::from(frame.width);
            f_height = u32::from(frame.height);
        } else {
            return Err(ImageError::ImageEnd);
        }

        self.reader.read_into_buffer(buf)?;

        let (width, height) = (u32::from(self.reader.width()), u32::from(self.reader.height()));
        if (left, top) != (0, 0) || (width, height) != (f_width, f_height) {
            // This is somewhat of an annoying case. The image we read into `buf` doesn't take up
            // the whole buffer and now we need to properly insert borders. For simplicity this code
            // currently takes advantage of the `ImageBuffer::from_fn` function to make a second
            // ImageBuffer that is properly positioned, and then copies it back into `buf`.
            //
            // TODO: Implement this without any allocation.

            // See the comments inside `<GifFrameIterator as Iterator>::next` about
            // the error handling of `from_raw`.
            let image = ImageBuffer::from_raw(f_width, f_height, &mut *buf).ok_or_else(
                || ImageError::UnsupportedError("Image dimensions are too large".into())
            )?;

            // Recover the full image
            let image_buffer = ImageBuffer::from_fn(width, height, |x, y| {
                let x = x.wrapping_sub(left);
                let y = y.wrapping_sub(top);
                if x < image.width() && y < image.height() {
                    *image.get_pixel(x, y)
                } else {
                    Rgba([0, 0, 0, 0])
                }
            });
            buf.copy_from_slice(&mut image_buffer.into_raw());
        }
        Ok(())
    }
}

struct GifFrameIterator<R: Read> {
    reader: gif::Reader<R>,

    width: u32,
    height: u32,

    non_disposed_frame: ImageBuffer<Rgba<u8>, Vec<u8>>,
}

impl<R: Read> GifFrameIterator<R> {
    fn new(decoder: GifDecoder<R>) -> GifFrameIterator<R> {
        let (width, height) = decoder.dimensions();

        // TODO: Avoid this cast
        let (width, height) = (width as u32, height as u32);

        // intentionally ignore the background color for web compatibility

        // create the first non disposed frame
        let non_disposed_frame = ImageBuffer::from_pixel(width, height, Rgba([0, 0, 0, 0]));

        GifFrameIterator {
            reader: decoder.reader,
            width,
            height,
            non_disposed_frame,
        }
    }
}

impl<R: Read> Iterator for GifFrameIterator<R> {
    type Item = ImageResult<animation::Frame>;

    fn next(&mut self) -> Option<ImageResult<animation::Frame>> {
        // begin looping over each frame
        let (left, top, delay, dispose, f_width, f_height);

        match self.reader.next_frame_info() {
            Ok(frame_info) => {
                if let Some(frame) = frame_info {
                    left = u32::from(frame.left);
                    top = u32::from(frame.top);
                    f_width = u32::from(frame.width);
                    f_height = u32::from(frame.height);

                    // frame.delay is in units of 10ms so frame.delay*10 is in ms
                    delay = Ratio::new(frame.delay * 10, 1);
                    dispose = frame.dispose;
                } else {
                    // no more frames
                    return None;
                }
            },
            Err(err) => return Some(Err(err.into())),
        }

        let mut vec = vec![0; self.reader.buffer_size()];
        if let Err(err) = self.reader.fill_buffer(&mut vec) {
            return Some(Err(err.into()));
        }

        // create the image buffer from the raw frame.
        // `buffer_size` uses wrapping arithmetics, thus might not report the
        // correct storage requirement if the result does not fit in `usize`.
        // on the other hand, `ImageBuffer::from_raw` detects overflow and
        // reports by returning `None`.
        let image_buffer_raw = match ImageBuffer::from_raw(f_width, f_height, vec) {
            Some(image_buffer_raw) => image_buffer_raw,
            None => {
                return Some(Err(ImageError::UnsupportedError(
                    "Image dimensions are too large".into(),
                )))
            }
        };

        // if `image_buffer_raw`'s frame exactly matches the entire image, then
        // use it directly.
        //
        // otherwise, `image_buffer_raw` represents a smaller image.
        // create a new image of the target size and place
        // `image_buffer_raw` within it. the outside region is filled with
        // transparent pixels.
        let mut image_buffer =
            full_image_from_frame(self.width, self.height, image_buffer_raw, left, top);

        // loop over all pixels, checking if any pixels from the non disposed
        // frame need to be used
        for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
            let previous_img_buffer = &self.non_disposed_frame;
            let adjusted_pixel: &mut Rgba<u8> = pixel;
            let previous_pixel: &Rgba<u8> = previous_img_buffer.get_pixel(x, y);

            let pixel_alpha = adjusted_pixel.channels()[3];

            // If a pixel is not visible then we show the non disposed frame pixel instead
            if pixel_alpha == 0 {
                adjusted_pixel.blend(previous_pixel);
            }
        }

        let frame = animation::Frame::from_parts(
            image_buffer.clone(), 0, 0, delay
        );

        match dispose {
            DisposalMethod::Any => {
                // do nothing
                // (completely replace this frame with the next)
            }
            DisposalMethod::Keep => {
                // do not dispose
                // (keep pixels from this frame)
                self.non_disposed_frame = image_buffer;
            }
            DisposalMethod::Background => {
                // restore to background color
                // (background shows through transparent pixels in the next frame)
                for y in top..min(top + f_height, self.height) {
                    for x in left..min(left + f_width, self.width) {
                        self.non_disposed_frame.put_pixel(x, y, Rgba([0, 0, 0, 0]));
                    }
                }
            }
            DisposalMethod::Previous => {
                // restore to previous
                // (dispose frames leaving the last none disposal frame)
            }
        };

        Some(Ok(frame))
    }
}

/// Given a frame subimage, construct a full image of size
/// `(screen_width, screen_height)` by placing it at the top-left coordinates
/// `(left, top)`. The remaining portion is filled with transparent pixels.
fn full_image_from_frame(
    screen_width: u32,
    screen_height: u32,
    image: crate::RgbaImage,
    left: u32,
    top: u32,
) -> crate::RgbaImage {
    if (left, top) == (0, 0) && (screen_width, screen_height) == (image.width(), image.height()) {
        image
    } else {
        ImageBuffer::from_fn(screen_width, screen_height, |x, y| {
            let x = x.wrapping_sub(left);
            let y = y.wrapping_sub(top);
            if x < image.width() && y < image.height() {
                *image.get_pixel(x, y)
            } else {
                Rgba([0, 0, 0, 0])
            }
        })
    }
}

impl<'a, R: Read + 'a> AnimationDecoder<'a> for GifDecoder<R> {
    fn into_frames(self) -> animation::Frames<'a> {
        animation::Frames::new(Box::new(GifFrameIterator::new(self)))
    }
}

/// GIF encoder.
pub struct Encoder<W: Write> {
    w: Option<W>,
    gif_encoder: Option<gif::Encoder<W>>,
}

impl<W: Write> Encoder<W> {
    /// Creates a new GIF encoder.
    pub fn new(w: W) -> Encoder<W> {
        Encoder {
            w: Some(w),
            gif_encoder: None,
        }
    }
    /// Encodes a frame.
    pub fn encode(&mut self, frame: &Frame) -> ImageResult<()> {
        let result;
        if let Some(ref mut encoder) = self.gif_encoder {
            result = encoder.write_frame(frame).map_err(|err| err.into());
        } else {
            let writer = self.w.take().unwrap();
            let mut encoder = gif::Encoder::new(writer, frame.width, frame.height, &[])?;
            result = encoder.write_frame(&frame).map_err(|err| err.into());
            self.gif_encoder = Some(encoder);
        }
        result
    }

    /// Encodes Frames.
    /// Consider using `try_encode_frames` instead to encode an `animation::Frames` like iterator.
    pub fn encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
    where
        F: IntoIterator<Item = animation::Frame>
    {
        for img_frame in frames {
            self.encode_single_frame(img_frame)?;
        }
        Ok(())
    }

    /// Try to encode a collection of `ImageResult<animation::Frame>` objects.
    /// Use this function to encode an `animation::Frames` like iterator.
    /// Whenever an `Err` item is encountered, that value is returned without further actions.
    pub fn try_encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
    where
        F: IntoIterator<Item = ImageResult<animation::Frame>>
    {
        for img_frame in frames {
            self.encode_single_frame(img_frame?)?;
        }
        Ok(())
    }

    fn encode_single_frame(&mut self, img_frame: animation::Frame) -> ImageResult<()> {
        // get the delay before converting img_frame
        let frame_delay = img_frame.delay().to_integer();
        // convert img_frame into RgbaImage
        let rbga_frame = img_frame.into_buffer();

        // Create the gif::Frame from the animation::Frame
        let mut frame = Frame::from_rgba(rbga_frame.width() as u16, rbga_frame.height() as u16, &mut rbga_frame.into_raw());
        frame.delay = frame_delay;

        // encode the gif::Frame
        self.encode(&frame)
    }
}

impl From<gif::DecodingError> for ImageError {
    fn from(err: gif::DecodingError) -> ImageError {
        use self::gif::DecodingError::*;
        match err {
            Format(desc) | Internal(desc) => ImageError::FormatError(desc.into()),
            Io(io_err) => ImageError::IoError(io_err),
        }
    }
}
<|endoftext|>


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

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

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

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

            <title>404 Not Found</title>

Not Found

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

    ";

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

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

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

HTTPTIN - HTTP tester in Rust and Rocket

    ";

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

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

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

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

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

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

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

trait ToResponse {
    fn status(&self) -> StatusCode {
        StatusCode::Ok
    }

    fn content_type(&self) -> ContentType {
        ContentType::plaintext()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(0)
    }

    fn content(&self) -> &[u8] {
        &[]
    }
}

impl ToResponse for StatusCode {
    fn status(&self) -> StatusCode {
        *self
    }
}

impl ToResponse for String {
    fn content_type(&self) -> ContentType {
        ContentType::html()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(self.as_bytes().len() as u64)
    }

    fn content(&self) -> &[u8] {
        self.as_bytes()
    }
}

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

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

            <title>404 Not Found</title>

Not Found

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

    ";

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

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

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

HTTPTIN - HTTP tester in Rust and Rocket

    ";

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

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

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

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

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

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