<commit_before>#![feature(libc, alloc, core, collections)]
#![warn(missing_docs)]

//! rust-vst2 is a rust implementation of the VST2.4 API
//!
//! # Plugins
//! All Plugins must implement the `Vst` trait and `std::default::Default`. The `vst_main!` macro
//! must also be called in order to export the necessary functions for the VST to function.
//!
//! ## `Vst` Trait
//! All methods in this trait have a default implementation except for the `get_info` method which
//! must be implemented by the Vst object. Any of the default implementations may be overriden for
//! custom functionality; the defaults do nothing on their own.
//!
//! ## `vst_main!` macro
//! `vst_main!` will export the necessary functions to create a proper VST. This must be called
//! with your VST struct name in order for the vst to work.
//!
//! ## Example plugin
//! A barebones VST plugin:
//!
//! ```no_run
//! #[macro_use]
//! extern crate vst2;
//! use std::default::Default;
//!
//! use vst2::{Vst, Info};
//!
//! struct BasicVst;
//!
//! impl Vst for BasicVst {
//!     fn get_info(&self) -> Info {
//!         Info {
//!             name: "BasicVst".to_string(),
//!
//!             ..Default::default()
//!         }
//!     }
//! }
//!
//! impl Default for BasicVst {
//!     fn default() -> BasicVst {
//!         BasicVst
//!     }
//! }
//!
//! vst_main!(BasicVst); //Important!
//! # fn main() {} //no_run
//! ```
//!
//! # Hosts
//! Hosts are currently not supported. TODO

extern crate collections;
extern crate libc;
extern crate num;
#[macro_use] extern crate log;
#[macro_use] extern crate bitflags;

use std::default::Default;
use std::{ptr, mem};
use std::iter::IntoIterator;

use libc::c_void;

pub mod buffer;
pub mod enums;
pub mod api;
pub mod editor;
mod interfaces;

use enums::flags::plugin::*;
use enums::{PluginCategory, CanDo, Supported};
use api::{HostCallback, AEffect};
pub use buffer::AudioBuffer;
use editor::Editor;

/// VST plugins are identified by a magic number. This corresponds to 0x56737450.
const VST_MAGIC: i32 = ('V' as i32) << 24 |
                       ('s' as i32) << 16 |
                       ('t' as i32) << 8  |
                       ('P' as i32) << 0  ;

/// Exports the necessary symbols for the plugin to be used by a vst host.
///
/// This macro takes a type which must implement the traits `Vst` and `std::default::Default`.
#[macro_export]
macro_rules! vst_main {
    ($t:ty) => {
        #[cfg(target_os = "mac")]
        pub extern "system" fn main_macho (callback: $crate::callbacks::HostCallback) -> *mut $crate::api::AEffect {
            VSTPluginMain(callback)
        }

        #[cfg(target_os = "windows")]
        pub extern "system" fn MAIN (callback: $crate::callbacks::HostCallback) -> *mut $crate::api::AEffect {
            VSTPluginMain(callback)
        }

        #[allow(non_snake_case, unused_variables)]
        #[no_mangle]
        pub extern "system" fn VSTPluginMain(callback: $crate::api::HostCallback) -> *mut $crate::api::AEffect {
            $crate::main::<$t>(callback)
        }
    }
}

/// Initializes a VST plugin and returns a raw pointer to an AEffect struct.
#[doc(hidden)]
pub fn main<T: Vst + Default>(callback: HostCallback) -> *mut AEffect {
    // 1 is audioMasterVersion TODO: abstract this
    if callback(ptr::null_mut(), 1, 0, 0, ptr::null_mut(), 0.0) == 0 {
        return ptr::null_mut();
    }

    let mut vst: T = Default::default();
    let info = vst.get_info().clone();
    trace!("Creating VST Instance...");

    unsafe { mem::transmute(Box::new(AEffect {
        magic: VST_MAGIC,
        dispatcher: interfaces::dispatch, // fn pointer

        _process: interfaces::process_deprecated, // fn pointer

        setParameter: interfaces::set_parameter, // fn pointer
        getParameter: interfaces::get_parameter, // fn pointer

        numPrograms: info.presets,
        numParams: info.parameters,
        numInputs: info.inputs,
        numOutputs: info.outputs,

        flags: {
            let mut flag = CAN_REPLACING;

            if info.f64_precision {
                flag = flag | CAN_DOUBLE_REPLACING;
            }

            if vst.get_editor().is_some() {
                flag = flag | HAS_EDITOR;
            }

            if info.preset_chunks {
                flag = flag | PROGRAM_CHUNKS;
            }

            if let PluginCategory::Synth = info.category {
                flag = flag | IS_SYNTH;
            }

            flag.bits()
        },

        reserved1: 0,
        reserved2: 0,

        initialDelay: 0,

        _realQualities: 0,
        _offQualities: 0,
        _ioRatio: 0.0,

        object: mem::transmute(Box::new(Box::new(vst) as Box<Vst>)),
        user: ptr::null_mut(),

        uniqueId: 0,
        version: 0001,

        processReplacing: interfaces::process_replacing, // fn pointer
        processReplacingF64: interfaces::process_replacing_f64, //fn pointer

        future: [0u8; 56]
    })) }
}

/// A structure representing static plugin information.
#[derive(Clone, Debug)]
pub struct Info {
    /// Plugin Name.
    pub name: String,

    /// Plugin Vendor.
    pub vendor: String,

    /// Number of different presets.
    pub presets: i32,

    /// Number of parameters.
    pub parameters: i32,

    /// Number of inputs.
    pub inputs: i32,

    /// Number of outputs.
    pub outputs: i32,

    /// Unique plugin ID. Can be registered with Steinberg to prevent conflicts with other plugins.
    ///
    /// This ID is used to identify a plugin during save and load of a preset and project.
    pub unique_id: i32,

    /// Plugin version (e.g. 0001 = `v0.0.0.1`, 1283 = `v1.2.8.3`).
    pub version: i32,

    /// Plugin category. Possible values are found in `enums::PluginCategory`.
    pub category: PluginCategory,

    //TODO: Doc
    pub initial_delay: i32,

    /// Indicates whether preset data is handled in formatless chunks. If false,
    /// host saves and restores plugins by reading/writing parameter data. If true, it is up to
    /// the plugin to manage saving preset data by implementing  the
    /// `{get, load}_{preset, bank}_chunks()` methods. Default is `false`.
    pub preset_chunks: bool,

    /// Indicates whether this plugin can process f64 based `AudioBuffer` buffers. Default is
    /// `false`.
    pub f64_precision: bool,

    //no_sound_in_stop: bool, //TODO: Implement this somehow
}

impl Default for Info {
    fn default() -> Info {
        Info {
            name: String::from_str("VST"),
            vendor: String::new(),

            presets: 1, // default preset
            parameters: 0,
            inputs: 2, // Stereo in,out
            outputs: 2,

            unique_id: 0,
            version: 0001, // v0.0.0.1

            category: PluginCategory::Effect,

            initial_delay: 0,

            preset_chunks: false,
            f64_precision: false,
        }
    }
}

/// Must be implemented by all VST plugins.
///
/// All methods except `get_info` provide a default implementation which does nothing and can be
/// safely overridden.
#[allow(unused_variables)]
pub trait Vst {
    /// This method must return an `Info` struct.
    fn get_info(&self) -> Info;

    /// Called when VST is initialized.
    fn init(&mut self) { trace!("Initialized vst."); }

    /// Set the current preset to the index specified by `preset`.
    fn change_preset(&mut self, preset: i32) { }

    /// Get the current preset index.
    fn get_preset_num(&mut self) -> i32 { 0 }

    /// Set the current preset name.
    fn set_preset_name(&mut self, name: String) { }

    /// Get the name of the preset at the index specified by `preset`.
    fn get_preset_name(&mut self, preset: i32) -> String { "".to_string() }

    /// Get parameter label for parameter at `index` (e.g. "db", "sec", "ms", "%").
    fn get_parameter_label(&mut self, index: i32) -> String { "".to_string() }

    /// Get the parameter value for parameter at `index` (e.g. "1.0", "150", "Plate", "Off").
    fn get_parameter_text(&mut self, index: i32) -> String {
        format!("{:.3}", self.get_parameter(index))
    }

    /// Get the name of parameter at `index`.
    fn get_parameter_name(&mut self, index: i32) -> String { format!("Param {}", index) }

    /// Get the value of paramater at `index`. Should be value between 0.0 and 1.0.
    fn get_parameter(&mut self, index: i32) -> f32 { 0.0 }

    /// Set the value of parameter at `index`. `value` is between 0.0 and 1.0.
    fn set_parameter(&mut self, index: i32, value: f32) { }

    /// Return whether parameter at `index` can be automated.
    fn can_be_automated(&mut self, index: i32) -> bool { false }

    /// Called when sample rate is changed by host.
    fn sample_rate_changed(&mut self, rate: f32) { }

    /// Called when block size is changed by host.
    fn block_size_changed(&mut self, size: i64) { }

    /// Called when plugin is turned on.
    fn on_resume(&mut self) { }

    /// Called when plugin is turned off.
    fn on_suspend(&mut self) { }

    /// Vendor specific handling.
    fn vendor_specific(&mut self, index: i32, value: isize, ptr: *mut c_void, opt: f32) { }

    /// Return whether plugin supports specified action.
    fn can_do(&mut self, can_do: CanDo) -> Supported {
        info!("Host is asking if plugin can: {:?}.", can_do);
        Supported::Maybe
    }

    /// Get the tail size of plugin when it is stopped. Used in offline processing as well.
    fn get_tail_size(&mut self) -> isize { 0 }

    /// Process an audio buffer containing `f32` values. TODO: Examples
    fn process(&mut self, buffer: AudioBuffer<f32>) {
        // For each input and output
        for (input, output) in buffer.zip() {
            // For each input sample and output sample in buffer
            for (in_frame, out_frame) in input.into_iter().zip(output.into_iter()) {
                *out_frame = *in_frame;
            }
        }
    }

    /// Process an audio buffer containing `f64` values. TODO: Examples
    fn process_f64(&mut self, buffer: AudioBuffer<f64>) {
        // For each input and output
        for (input, output) in buffer.zip() {
            // For each input sample and output sample in buffer
            for (in_frame, out_frame) in input.into_iter().zip(output.into_iter()) {
                *out_frame = *in_frame;
            }
        }
    }

    /// Return handle to plugin editor if supported.
    fn get_editor(&mut self) -> Option<&mut Editor> { None }

    /// If `preset_chunks` is set to true in plugin info, this should return the raw chunk data for
    /// the current preset.
    fn get_preset_chunks(&mut self) -> Vec<u8> { Vec::new() }

    /// If `preset_chunks` is set to true in plugin info, this should return the raw chunk data for
    /// the current plugin bank.
    fn get_bank_chunks(&mut self) -> Vec<u8> { Vec::new() }

    /// If `preset_chunks` is set to true in plugin info, this should load a preset from the given
    /// chunk data.
    fn load_preset_chunks(&mut self, data: Vec<u8>) {}

    /// If `preset_chunks` is set to true in plugin info, this should load a preset bank from the
    /// given chunk data.
    fn load_bank_chunks(&mut self, data: Vec<u8>) {}
}

#[cfg(test)]
mod tests {
    use std::default::Default;
    use std::ptr;

    use libc::c_void;

    use Vst;
    use Info;
    use main;
    use api::AEffect;

    #[derive(Default)]
    struct TestVst;

    impl Vst for TestVst {
        fn get_info(&self) -> Info {
            Info {
                name: "TestVST".to_string(),
                ..Default::default()
            }
        }
    }

    fn pass_callback(_effect: *mut AEffect, _opcode: i32, _index: i32, _value: isize, _ptr: *mut c_void, _opt: f32) -> isize {
        1
    }

    fn fail_callback(_effect: *mut AEffect, _opcode: i32, _index: i32, _value: isize, _ptr: *mut c_void, _opt: f32) -> isize {
        0
    }

    #[test]
    fn host_callback() {
        assert_eq!(main::<TestVst>(fail_callback), ptr::null_mut());
    }

    #[test]
    fn aeffect_created() {
        let aeffect = main::<TestVst>(pass_callback);
        assert!(!aeffect.is_null());
    }

    #[test]
    fn vst_drop() {
        use std::mem;

        static mut drop_test: bool = false;

        impl Drop for TestVst {
            fn drop(&mut self) {
                unsafe { drop_test = true; }
            }
        }

        let aeffect = main::<TestVst>(pass_callback);
        assert!(!aeffect.is_null());

        unsafe { drop(mem::transmute::<*mut AEffect, Box<AEffect>>(aeffect)) };

        // Assert that the VST is shut down and dropped.
        assert!(unsafe { drop_test });
    }

    #[test]
    fn vst_deref() {
        let aeffect = main::<TestVst>(pass_callback);
        assert!(!aeffect.is_null());

        let vst = unsafe { (*aeffect).get_vst() };
        // Assert that deref works correctly.
        assert!(vst.get_info().name == "TestVST");
    }
}
<commit_msg>Shorter doc example.<commit_after>#![feature(libc, alloc, core, collections)]
#![warn(missing_docs)]

//! rust-vst2 is a rust implementation of the VST2.4 API
//!
//! # Plugins
//! All Plugins must implement the `Vst` trait and `std::default::Default`. The `vst_main!` macro
//! must also be called in order to export the necessary functions for the VST to function.
//!
//! ## `Vst` Trait
//! All methods in this trait have a default implementation except for the `get_info` method which
//! must be implemented by the Vst object. Any of the default implementations may be overriden for
//! custom functionality; the defaults do nothing on their own.
//!
//! ## `vst_main!` macro
//! `vst_main!` will export the necessary functions to create a proper VST. This must be called
//! with your VST struct name in order for the vst to work.
//!
//! ## Example plugin
//! A barebones VST plugin:
//!
//! ```no_run
//! #[macro_use]
//! extern crate vst2;
//! use std::default::Default;
//!
//! use vst2::{Vst, Info};
//!
//! #[derive(Default)]
//! struct BasicVst;
//!
//! impl Vst for BasicVst {
//!     fn get_info(&self) -> Info {
//!         Info {
//!             name: "BasicVst".to_string(),
//!
//!             ..Default::default()
//!         }
//!     }
//! }
//!
//! vst_main!(BasicVst); //Important!
//! # fn main() {} //no_run
//! ```
//!
//! # Hosts
//! Hosts are currently not supported. TODO

extern crate collections;
extern crate libc;
extern crate num;
#[macro_use] extern crate log;
#[macro_use] extern crate bitflags;

use std::default::Default;
use std::{ptr, mem};
use std::iter::IntoIterator;

use libc::c_void;

pub mod buffer;
pub mod enums;
pub mod api;
pub mod editor;
mod interfaces;

use enums::flags::plugin::*;
use enums::{PluginCategory, CanDo, Supported};
use api::{HostCallback, AEffect};
pub use buffer::AudioBuffer;
use editor::Editor;

/// VST plugins are identified by a magic number. This corresponds to 0x56737450.
const VST_MAGIC: i32 = ('V' as i32) << 24 |
                       ('s' as i32) << 16 |
                       ('t' as i32) << 8  |
                       ('P' as i32) << 0  ;

/// Exports the necessary symbols for the plugin to be used by a vst host.
///
/// This macro takes a type which must implement the traits `Vst` and `std::default::Default`.
#[macro_export]
macro_rules! vst_main {
    ($t:ty) => {
        #[cfg(target_os = "mac")]
        pub extern "system" fn main_macho (callback: $crate::callbacks::HostCallback) -> *mut $crate::api::AEffect {
            VSTPluginMain(callback)
        }

        #[cfg(target_os = "windows")]
        pub extern "system" fn MAIN (callback: $crate::callbacks::HostCallback) -> *mut $crate::api::AEffect {
            VSTPluginMain(callback)
        }

        #[allow(non_snake_case, unused_variables)]
        #[no_mangle]
        pub extern "system" fn VSTPluginMain(callback: $crate::api::HostCallback) -> *mut $crate::api::AEffect {
            $crate::main::<$t>(callback)
        }
    }
}

/// Initializes a VST plugin and returns a raw pointer to an AEffect struct.
#[doc(hidden)]
pub fn main<T: Vst + Default>(callback: HostCallback) -> *mut AEffect {
    // 1 is audioMasterVersion TODO: abstract this
    if callback(ptr::null_mut(), 1, 0, 0, ptr::null_mut(), 0.0) == 0 {
        return ptr::null_mut();
    }

    let mut vst: T = Default::default();
    let info = vst.get_info().clone();
    trace!("Creating VST Instance...");

    unsafe { mem::transmute(Box::new(AEffect {
        magic: VST_MAGIC,
        dispatcher: interfaces::dispatch, // fn pointer

        _process: interfaces::process_deprecated, // fn pointer

        setParameter: interfaces::set_parameter, // fn pointer
        getParameter: interfaces::get_parameter, // fn pointer

        numPrograms: info.presets,
        numParams: info.parameters,
        numInputs: info.inputs,
        numOutputs: info.outputs,

        flags: {
            let mut flag = CAN_REPLACING;

            if info.f64_precision {
                flag = flag | CAN_DOUBLE_REPLACING;
            }

            if vst.get_editor().is_some() {
                flag = flag | HAS_EDITOR;
            }

            if info.preset_chunks {
                flag = flag | PROGRAM_CHUNKS;
            }

            if let PluginCategory::Synth = info.category {
                flag = flag | IS_SYNTH;
            }

            flag.bits()
        },

        reserved1: 0,
        reserved2: 0,

        initialDelay: 0,

        _realQualities: 0,
        _offQualities: 0,
        _ioRatio: 0.0,

        object: mem::transmute(Box::new(Box::new(vst) as Box<Vst>)),
        user: ptr::null_mut(),

        uniqueId: 0,
        version: 0001,

        processReplacing: interfaces::process_replacing, // fn pointer
        processReplacingF64: interfaces::process_replacing_f64, //fn pointer

        future: [0u8; 56]
    })) }
}

/// A structure representing static plugin information.
#[derive(Clone, Debug)]
pub struct Info {
    /// Plugin Name.
    pub name: String,

    /// Plugin Vendor.
    pub vendor: String,

    /// Number of different presets.
    pub presets: i32,

    /// Number of parameters.
    pub parameters: i32,

    /// Number of inputs.
    pub inputs: i32,

    /// Number of outputs.
    pub outputs: i32,

    /// Unique plugin ID. Can be registered with Steinberg to prevent conflicts with other plugins.
    ///
    /// This ID is used to identify a plugin during save and load of a preset and project.
    pub unique_id: i32,

    /// Plugin version (e.g. 0001 = `v0.0.0.1`, 1283 = `v1.2.8.3`).
    pub version: i32,

    /// Plugin category. Possible values are found in `enums::PluginCategory`.
    pub category: PluginCategory,

    //TODO: Doc
    pub initial_delay: i32,

    /// Indicates whether preset data is handled in formatless chunks. If false,
    /// host saves and restores plugins by reading/writing parameter data. If true, it is up to
    /// the plugin to manage saving preset data by implementing  the
    /// `{get, load}_{preset, bank}_chunks()` methods. Default is `false`.
    pub preset_chunks: bool,

    /// Indicates whether this plugin can process f64 based `AudioBuffer` buffers. Default is
    /// `false`.
    pub f64_precision: bool,

    //no_sound_in_stop: bool, //TODO: Implement this somehow
}

impl Default for Info {
    fn default() -> Info {
        Info {
            name: String::from_str("VST"),
            vendor: String::new(),

            presets: 1, // default preset
            parameters: 0,
            inputs: 2, // Stereo in,out
            outputs: 2,

            unique_id: 0,
            version: 0001, // v0.0.0.1

            category: PluginCategory::Effect,

            initial_delay: 0,

            preset_chunks: false,
            f64_precision: false,
        }
    }
}

/// Must be implemented by all VST plugins.
///
/// All methods except `get_info` provide a default implementation which does nothing and can be
/// safely overridden.
#[allow(unused_variables)]
pub trait Vst {
    /// This method must return an `Info` struct.
    fn get_info(&self) -> Info;

    /// Called when VST is initialized.
    fn init(&mut self) { trace!("Initialized vst."); }

    /// Set the current preset to the index specified by `preset`.
    fn change_preset(&mut self, preset: i32) { }

    /// Get the current preset index.
    fn get_preset_num(&mut self) -> i32 { 0 }

    /// Set the current preset name.
    fn set_preset_name(&mut self, name: String) { }

    /// Get the name of the preset at the index specified by `preset`.
    fn get_preset_name(&mut self, preset: i32) -> String { "".to_string() }

    /// Get parameter label for parameter at `index` (e.g. "db", "sec", "ms", "%").
    fn get_parameter_label(&mut self, index: i32) -> String { "".to_string() }

    /// Get the parameter value for parameter at `index` (e.g. "1.0", "150", "Plate", "Off").
    fn get_parameter_text(&mut self, index: i32) -> String {
        format!("{:.3}", self.get_parameter(index))
    }

    /// Get the name of parameter at `index`.
    fn get_parameter_name(&mut self, index: i32) -> String { format!("Param {}", index) }

    /// Get the value of paramater at `index`. Should be value between 0.0 and 1.0.
    fn get_parameter(&mut self, index: i32) -> f32 { 0.0 }

    /// Set the value of parameter at `index`. `value` is between 0.0 and 1.0.
    fn set_parameter(&mut self, index: i32, value: f32) { }

    /// Return whether parameter at `index` can be automated.
    fn can_be_automated(&mut self, index: i32) -> bool { false }

    /// Called when sample rate is changed by host.
    fn sample_rate_changed(&mut self, rate: f32) { }

    /// Called when block size is changed by host.
    fn block_size_changed(&mut self, size: i64) { }

    /// Called when plugin is turned on.
    fn on_resume(&mut self) { }

    /// Called when plugin is turned off.
    fn on_suspend(&mut self) { }

    /// Vendor specific handling.
    fn vendor_specific(&mut self, index: i32, value: isize, ptr: *mut c_void, opt: f32) { }

    /// Return whether plugin supports specified action.
    fn can_do(&mut self, can_do: CanDo) -> Supported {
        info!("Host is asking if plugin can: {:?}.", can_do);
        Supported::Maybe
    }

    /// Get the tail size of plugin when it is stopped. Used in offline processing as well.
    fn get_tail_size(&mut self) -> isize { 0 }

    /// Process an audio buffer containing `f32` values. TODO: Examples
    fn process(&mut self, buffer: AudioBuffer<f32>) {
        // For each input and output
        for (input, output) in buffer.zip() {
            // For each input sample and output sample in buffer
            for (in_frame, out_frame) in input.into_iter().zip(output.into_iter()) {
                *out_frame = *in_frame;
            }
        }
    }

    /// Process an audio buffer containing `f64` values. TODO: Examples
    fn process_f64(&mut self, buffer: AudioBuffer<f64>) {
        // For each input and output
        for (input, output) in buffer.zip() {
            // For each input sample and output sample in buffer
            for (in_frame, out_frame) in input.into_iter().zip(output.into_iter()) {
                *out_frame = *in_frame;
            }
        }
    }

    /// Return handle to plugin editor if supported.
    fn get_editor(&mut self) -> Option<&mut Editor> { None }

    /// If `preset_chunks` is set to true in plugin info, this should return the raw chunk data for
    /// the current preset.
    fn get_preset_chunks(&mut self) -> Vec<u8> { Vec::new() }

    /// If `preset_chunks` is set to true in plugin info, this should return the raw chunk data for
    /// the current plugin bank.
    fn get_bank_chunks(&mut self) -> Vec<u8> { Vec::new() }

    /// If `preset_chunks` is set to true in plugin info, this should load a preset from the given
    /// chunk data.
    fn load_preset_chunks(&mut self, data: Vec<u8>) {}

    /// If `preset_chunks` is set to true in plugin info, this should load a preset bank from the
    /// given chunk data.
    fn load_bank_chunks(&mut self, data: Vec<u8>) {}
}

#[cfg(test)]
mod tests {
    use std::default::Default;
    use std::ptr;

    use libc::c_void;

    use Vst;
    use Info;
    use main;
    use api::AEffect;

    #[derive(Default)]
    struct TestVst;

    impl Vst for TestVst {
        fn get_info(&self) -> Info {
            Info {
                name: "TestVST".to_string(),
                ..Default::default()
            }
        }
    }

    fn pass_callback(_effect: *mut AEffect, _opcode: i32, _index: i32, _value: isize, _ptr: *mut c_void, _opt: f32) -> isize {
        1
    }

    fn fail_callback(_effect: *mut AEffect, _opcode: i32, _index: i32, _value: isize, _ptr: *mut c_void, _opt: f32) -> isize {
        0
    }

    #[test]
    fn host_callback() {
        assert_eq!(main::<TestVst>(fail_callback), ptr::null_mut());
    }

    #[test]
    fn aeffect_created() {
        let aeffect = main::<TestVst>(pass_callback);
        assert!(!aeffect.is_null());
    }

    #[test]
    fn vst_drop() {
        use std::mem;

        static mut drop_test: bool = false;

        impl Drop for TestVst {
            fn drop(&mut self) {
                unsafe { drop_test = true; }
            }
        }

        let aeffect = main::<TestVst>(pass_callback);
        assert!(!aeffect.is_null());

        unsafe { drop(mem::transmute::<*mut AEffect, Box<AEffect>>(aeffect)) };

        // Assert that the VST is shut down and dropped.
        assert!(unsafe { drop_test });
    }

    #[test]
    fn vst_deref() {
        let aeffect = main::<TestVst>(pass_callback);
        assert!(!aeffect.is_null());

        let vst = unsafe { (*aeffect).get_vst() };
        // Assert that deref works correctly.
        assert!(vst.get_info().name == "TestVST");
    }
}
<|endoftext|>


<commit_before>//! # Overview
//!
//! This crate provides native rust implementations of image encoding and decoding as well as some
//! basic image manipulation functions. Additional documentation can currently also be found in the
//! [README.md file which is most easily viewed on
//! github](https://github.com/image-rs/image/blob/master/README.md).
//!
//! There are two core problems for which this library provides solutions: a unified interface for image
//! encodings and simple generic buffers for their content. It's possible to use either feature
//! without the other. The focus is on a small and stable set of common operations that can be
//! supplemented by other specialized crates. The library also prefers safe solutions with few
//! dependencies.
//!
//! # High level API
//!
//! Load images using [`io::Reader`]:
//!
//! ```rust,no_run
//! # use std::io::Cursor;
//! use image::io::Reader as ImageReader;
//! # fn main() -> Result<(), image::ImageError> {
//! # let bytes = vec![0u8];
//!
//! let img = ImageReader::open("myimage.png")?.decode()?;
//! let img2 = ImageReader::new(Cursor::new(bytes)).decode()?;
//! # Ok(())
//! # }
//! ```
//!
//! And save them using [`save`] or [`write_to`] methods:
//!
//! ```rust,no_run
//! # use std::io::Write;
//! # use image::ImageOutputFormat;
//! # use image::DynamicImage;
//! # #[cfg(feature = "png")]
//! # fn main() -> Result<(), image::ImageError> {
//! # let img: DynamicImage = unimplemented!();
//! # let img2: DynamicImage = unimplemented!();
//! img.save("empty.jpg")?;
//!
//! let mut bytes: Vec<u8> = Vec::new();
//! img2.write_to(&mut bytes, image::ImageOutputFormat::Png)?;
//! # Ok(())
//! # }
//! ```
//!
//! With default features, the crate includes support for [many common image formats](codecs/index.html#supported-formats).
//!
//! [`save`]: enum.DynamicImage.html#method.save
//! [`write_to`]: enum.DynamicImage.html#method.write_to
//! [`io::Reader`]: io/struct.Reader.html
//!
//! # Image buffers
//!
//! The two main types for storing images:
//! * [`ImageBuffer`] which holds statically typed image contents.
//! * [`DynamicImage`] which is an enum over the supported ImageBuffer formats
//!     and supports conversions between them.
//!
//! As well as a few more specialized options:
//! * [`GenericImage`] trait for a mutable image buffer.
//! * [`GenericImageView`] trait for read only references to a GenericImage.
//! * [`flat`] module containing types for interoperability with generic channel
//!     matrices and foreign interfaces.
//!
//! [`GenericImageView`]: trait.GenericImageView.html
//! [`GenericImage`]: trait.GenericImage.html
//! [`ImageBuffer`]: struct.ImageBuffer.html
//! [`DynamicImage`]: enum.DynamicImage.html
//! [`flat`]: flat/index.html
//!
//! # Low level encoding/decoding API
//!
//! The [`ImageDecoder`] and [`ImageDecoderExt`] traits are implemented for many image file
//! formats. They decode image data by directly on raw byte slices. Given an ImageDecoder, you can
//! produce a DynamicImage via [`DynamicImage::from_decoder`].
//!
//! [`ImageEncoder`] provides the analogous functionality for encoding image data.
//!
//! [`DynamicImage::from_decoder`]: enum.DynamicImage.html#method.from_decoder
//! [`ImageDecoderExt`]: trait.ImageDecoderExt.html
//! [`ImageDecoder`]: trait.ImageDecoder.html
//! [`ImageEncoder`]: trait.ImageEncoder.html
#![warn(missing_docs)]
#![warn(unused_qualifications)]
#![deny(unreachable_pub)]
#![deny(deprecated)]
#![deny(missing_copy_implementations)]
#![cfg_attr(all(test, feature = "benchmarks"), feature(test))]
// it's a bit of a pain otherwise
#![allow(clippy::many_single_char_names)]

#[cfg(all(test, feature = "benchmarks"))]
extern crate test;

#[cfg(test)]
#[macro_use]
extern crate quickcheck;

use std::io::Write;

pub use crate::color::{ColorType, ExtendedColorType};

pub use crate::color::{Luma, LumaA, Rgb, Rgba, Bgr, Bgra};

pub use crate::error::{ImageError, ImageResult};

pub use crate::image::{AnimationDecoder,
                GenericImage,
                GenericImageView,
                ImageDecoder,
                ImageDecoderExt,
                ImageEncoder,
                ImageFormat,
                ImageOutputFormat,
                Progress,
                // Iterators
                Pixels,
                SubImage};

pub use crate::buffer_::{
                 GrayAlphaImage,
                 GrayImage,
                 // Image types
                 ImageBuffer,
                 RgbImage,
                 RgbaImage};

pub use crate::flat::FlatSamples;

// Traits
pub use crate::traits::{EncodableLayout, Primitive, Pixel};

// Opening and loading images
pub use crate::io::free_functions::{guess_format, load};
pub use crate::dynimage::{load_from_memory, load_from_memory_with_format, open,
                   save_buffer, save_buffer_with_format, image_dimensions};

pub use crate::dynimage::DynamicImage;

pub use crate::animation::{Delay, Frame, Frames};

// More detailed error type
pub mod error;

/// Iterators and other auxiliary structure for the `ImageBuffer` type.
pub mod buffer {
    // Only those not exported at the top-level
    pub use crate::buffer_::{
        ConvertBuffer,
        EnumeratePixels,
        EnumeratePixelsMut,
        EnumerateRows,
        EnumerateRowsMut,
        Pixels,
        PixelsMut,
        Rows,
        RowsMut,
    };
}

// Math utils
pub mod math;

// Image processing functions
pub mod imageops;

// Io bindings
pub mod io;

// Buffer representations for ffi.
pub mod flat;

/// Encoding and decoding for various image file formats.
///
/// # Supported formats
///
/// | Format | Decoding | Encoding |
/// | ------ | -------- | -------- |
/// | PNG    | All supported color types | Same as decoding |
/// | JPEG   | Baseline and progressive | Baseline JPEG |
/// | GIF    | Yes | Yes |
/// | BMP    | Yes | RGB8, RGBA8, Gray8, GrayA8 |
/// | ICO    | Yes | Yes |
/// | TIFF   | Baseline(no fax support) + LZW + PackBits | RGB8, RGBA8, Gray8 |
/// | WebP   | Lossy(Luma channel only) | No |
/// | PNM    | PBM, PGM, PPM, standard PAM | Yes |
/// | DDS    | DXT1, DXT3, DXT5 | No |
/// | TGA    | Yes | RGB8, RGBA8, BGR8, BGRA8, Gray8, GrayA8 |
/// | farbfeld | Yes | Yes |
///
/// ## A note on format specific features
///
/// One of the main goals of `image` is stability, in runtime but also for programmers. This
/// ensures that performance as well as safety fixes reach a majority of its user base with little
/// effort. Re-exporting all details of its dependencies would run counter to this goal as it
/// linked _all_ major version bumps between them and `image`. As such, we are wary of exposing too
/// many details, or configuration options, that are not shared between different image formats.
///
/// Nevertheless, the advantage of precise control is hard to ignore. We will thus consider
/// _wrappers_, not direct re-exports, in either of the following cases:
///
/// 1. A standard specifies that configuration _x_ is required for decoders/encoders and there
///    exists an essentially canonical way to control it.
/// 2. At least two different implementations agree on some (sub-)set of features in practice.
/// 3. A technical argument including measurements of the performance, space benefits, or otherwise
///    objectively quantified benefits can be made, and the added interface is unlikely to require
///    breaking changes.
///
/// Features that fulfill two or more criteria are preferred.
///
/// Re-exports of dependencies that reach version `1` will be discussed when it happens.
pub mod codecs {
    #[cfg(feature = "avif")]
    pub mod avif;
    #[cfg(feature = "bmp")]
    pub mod bmp;
    #[cfg(feature = "dds")]
    pub mod dds;
    #[cfg(feature = "dxt")]
    pub mod dxt;
    #[cfg(feature = "farbfeld")]
    pub mod farbfeld;
    #[cfg(feature = "gif")]
    pub mod gif;
    #[cfg(feature = "hdr")]
    pub mod hdr;
    #[cfg(feature = "ico")]
    pub mod ico;
    #[cfg(feature = "jpeg")]
    pub mod jpeg;
    #[cfg(feature = "png")]
    pub mod png;
    #[cfg(feature = "pnm")]
    pub mod pnm;
    #[cfg(feature = "tga")]
    pub mod tga;
    #[cfg(feature = "tiff")]
    pub mod tiff;
    #[cfg(feature = "webp")]
    pub mod webp;
}

#[cfg(feature = "avif")]
#[deprecated = "Use codecs::avif instead"]
pub mod avif {
    //! Encoding of AVIF images.
    pub use crate::codecs::avif::AvifEncoder;
}
#[cfg(feature = "bmp")]
#[deprecated = "Use codecs::bmp instead"]
pub mod bmp {
    //! Decoding and Encoding of BMP Images
    #[allow(deprecated)]
    pub use crate::codecs::bmp::{BMPEncoder, BmpDecoder, BmpEncoder};
}
#[cfg(feature = "dds")]
#[deprecated = "Use codecs::dds instead"]
pub mod dds {
    //! Decoding of DDS images
    pub use crate::codecs::dds::DdsDecoder;
}
#[cfg(feature = "dxt")]
#[deprecated = "Use codecs:: instead"]
pub mod dxt {
    //! Decoding of DXT (S3TC) compression
    #[allow(deprecated)]
    pub use crate::codecs::dxt::{
        DXTEncoder, DXTReader, DXTVariant, DxtDecoder, DxtEncoder, DxtReader, DxtVariant,
    };
}
#[cfg(feature = "farbfeld")]
#[deprecated = "Use codecs::farbfeld instead"]
pub mod farbfeld {
    //! Decoding of farbfeld images
    pub use crate::codecs::farbfeld::{FarbfeldDecoder, FarbfeldEncoder, FarbfeldReader};
}
#[cfg(feature = "gif")]
#[deprecated = "Use codecs::gif instead"]
pub mod gif {
    //! Decoding of GIF Images
    #[allow(deprecated)]
    pub use crate::codecs::gif::{Encoder, GifDecoder, GifEncoder, GifReader};
}
#[cfg(feature = "hdr")]
#[deprecated = "Use codecs::hdr instead"]
pub mod hdr {
    //! Decoding of Radiance HDR Images
    #[allow(deprecated)]
    pub use crate::codecs::hdr::{
        read_raw_file, rgbe8, to_rgbe8, HDRAdapter, HDREncoder, HDRImageDecoderIterator,
        HDRMetadata, HdrAdapter, HdrDecoder, HdrEncoder, HdrImageDecoderIterator, HdrMetadata,
        HdrReader, RGBE8Pixel, Rgbe8Pixel, SIGNATURE,
    };
}
#[cfg(feature = "ico")]
#[deprecated = "Use codecs::ico instead"]
pub mod ico {
    //! Decoding and Encoding of ICO files
    #[allow(deprecated)]
    pub use crate::codecs::ico::{ICOEncoder, IcoDecoder, IcoEncoder};
}
#[cfg(feature = "jpeg")]
#[deprecated = "Use codecs::jpeg instead"]
pub mod jpeg {
    //! Decoding and Encoding of JPEG Images
    #[allow(deprecated)]
    pub use crate::codecs::jpeg::{
        JPEGEncoder, JpegDecoder, JpegEncoder, PixelDensity, PixelDensityUnit,
    };
}
#[cfg(feature = "png")]
#[deprecated = "Use codecs::png instead"]
pub mod png {
    //! Decoding and Encoding of PNG Images
    #[allow(deprecated)]
    pub use crate::codecs::png::{
        ApngDecoder, PNGEncoder, PNGReader, PngDecoder, PngEncoder, PngReader,
    };
}
#[cfg(feature = "pnm")]
#[deprecated = "Use codecs::pnm instead"]
pub mod pnm {
    //! Decoding and Encoding of netpbm image formats (pbm, pgm, ppm and pam)
    #[allow(deprecated)]
    pub use crate::codecs::pnm::{
        ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PNMEncoder, PNMHeader,
        PNMSubtype, PixmapHeader, PnmDecoder, PnmEncoder, PnmHeader, PnmSubtype, SampleEncoding,
    };
}
#[cfg(feature = "tga")]
#[deprecated = "Use codecs::tga instead"]
pub mod tga {
    //! Decoding and Encoding of TGA Images
    #[allow(deprecated)]
    pub use crate::codecs::tga::{TgaDecoder, TgaEncoder};
}
#[cfg(feature = "tiff")]
#[deprecated = "Use codecs::tiff instead"]
pub mod tiff {
    //! Decoding and Encoding of TIFF Images
    #[allow(deprecated)]
    pub use crate::codecs::tiff::{TiffDecoder, TiffEncoder, TiffReader};
}
#[cfg(feature = "webp")]
#[deprecated = "Use codecs::webp instead"]
pub mod webp {
    //! Decoding of WebP Images
    #[allow(deprecated)]
    pub use crate::codecs::webp::{vp8, WebPDecoder};
}

mod animation;
#[path = "buffer.rs"]
mod buffer_;
mod color;
mod dynimage;
mod image;
mod traits;
mod utils;

// Can't use the macro-call itself within the `doc` attribute. So force it to eval it as part of
// the macro invocation.
//
// The inspiration for the macro and implementation is from
// <https://github.com/GuillaumeGomez/doc-comment>
//
// MIT License
//
// Copyright (c) 2018 Guillaume Gomez
macro_rules! insert_as_doc {
    { $content:expr } => {
        #[doc = $content] extern { }
    }
}

// Provides the README.md as doc, to ensure the example works!
insert_as_doc!(include_str!("../README.md"));

// Copies data from `src` to `dst`
//
// Panics if the length of `dst` is less than the length of `src`.
#[inline]
fn copy_memory(src: &[u8], mut dst: &mut [u8]) {
    let len_src = src.len();
    assert!(dst.len() >= len_src);
    dst.write_all(src).unwrap();
}
<commit_msg>Update src/lib.rs<commit_after>//! # Overview
//!
//! This crate provides native rust implementations of image encoding and decoding as well as some
//! basic image manipulation functions. Additional documentation can currently also be found in the
//! [README.md file which is most easily viewed on
//! github](https://github.com/image-rs/image/blob/master/README.md).
//!
//! There are two core problems for which this library provides solutions: a unified interface for image
//! encodings and simple generic buffers for their content. It's possible to use either feature
//! without the other. The focus is on a small and stable set of common operations that can be
//! supplemented by other specialized crates. The library also prefers safe solutions with few
//! dependencies.
//!
//! # High level API
//!
//! Load images using [`io::Reader`]:
//!
//! ```rust,no_run
//! # use std::io::Cursor;
//! use image::io::Reader as ImageReader;
//! # fn main() -> Result<(), image::ImageError> {
//! # let bytes = vec![0u8];
//!
//! let img = ImageReader::open("myimage.png")?.decode()?;
//! let img2 = ImageReader::new(Cursor::new(bytes)).decode()?;
//! # Ok(())
//! # }
//! ```
//!
//! And save them using [`save`] or [`write_to`] methods:
//!
//! ```rust,no_run
//! # use std::io::Write;
//! # use image::ImageOutputFormat;
//! # use image::DynamicImage;
//! # #[cfg(feature = "png")]
//! # fn main() -> Result<(), image::ImageError> {
//! # let img: DynamicImage = unimplemented!();
//! # let img2: DynamicImage = unimplemented!();
//! img.save("empty.jpg")?;
//!
//! let mut bytes: Vec<u8> = Vec::new();
//! img2.write_to(&mut bytes, image::ImageOutputFormat::Png)?;
//! # Ok(())
//! # }
//! # #[cfg(not(feature = "png"))] fn main() {}
//! ```
//!
//! With default features, the crate includes support for [many common image formats](codecs/index.html#supported-formats).
//!
//! [`save`]: enum.DynamicImage.html#method.save
//! [`write_to`]: enum.DynamicImage.html#method.write_to
//! [`io::Reader`]: io/struct.Reader.html
//!
//! # Image buffers
//!
//! The two main types for storing images:
//! * [`ImageBuffer`] which holds statically typed image contents.
//! * [`DynamicImage`] which is an enum over the supported ImageBuffer formats
//!     and supports conversions between them.
//!
//! As well as a few more specialized options:
//! * [`GenericImage`] trait for a mutable image buffer.
//! * [`GenericImageView`] trait for read only references to a GenericImage.
//! * [`flat`] module containing types for interoperability with generic channel
//!     matrices and foreign interfaces.
//!
//! [`GenericImageView`]: trait.GenericImageView.html
//! [`GenericImage`]: trait.GenericImage.html
//! [`ImageBuffer`]: struct.ImageBuffer.html
//! [`DynamicImage`]: enum.DynamicImage.html
//! [`flat`]: flat/index.html
//!
//! # Low level encoding/decoding API
//!
//! The [`ImageDecoder`] and [`ImageDecoderExt`] traits are implemented for many image file
//! formats. They decode image data by directly on raw byte slices. Given an ImageDecoder, you can
//! produce a DynamicImage via [`DynamicImage::from_decoder`].
//!
//! [`ImageEncoder`] provides the analogous functionality for encoding image data.
//!
//! [`DynamicImage::from_decoder`]: enum.DynamicImage.html#method.from_decoder
//! [`ImageDecoderExt`]: trait.ImageDecoderExt.html
//! [`ImageDecoder`]: trait.ImageDecoder.html
//! [`ImageEncoder`]: trait.ImageEncoder.html
#![warn(missing_docs)]
#![warn(unused_qualifications)]
#![deny(unreachable_pub)]
#![deny(deprecated)]
#![deny(missing_copy_implementations)]
#![cfg_attr(all(test, feature = "benchmarks"), feature(test))]
// it's a bit of a pain otherwise
#![allow(clippy::many_single_char_names)]

#[cfg(all(test, feature = "benchmarks"))]
extern crate test;

#[cfg(test)]
#[macro_use]
extern crate quickcheck;

use std::io::Write;

pub use crate::color::{ColorType, ExtendedColorType};

pub use crate::color::{Luma, LumaA, Rgb, Rgba, Bgr, Bgra};

pub use crate::error::{ImageError, ImageResult};

pub use crate::image::{AnimationDecoder,
                GenericImage,
                GenericImageView,
                ImageDecoder,
                ImageDecoderExt,
                ImageEncoder,
                ImageFormat,
                ImageOutputFormat,
                Progress,
                // Iterators
                Pixels,
                SubImage};

pub use crate::buffer_::{
                 GrayAlphaImage,
                 GrayImage,
                 // Image types
                 ImageBuffer,
                 RgbImage,
                 RgbaImage};

pub use crate::flat::FlatSamples;

// Traits
pub use crate::traits::{EncodableLayout, Primitive, Pixel};

// Opening and loading images
pub use crate::io::free_functions::{guess_format, load};
pub use crate::dynimage::{load_from_memory, load_from_memory_with_format, open,
                   save_buffer, save_buffer_with_format, image_dimensions};

pub use crate::dynimage::DynamicImage;

pub use crate::animation::{Delay, Frame, Frames};

// More detailed error type
pub mod error;

/// Iterators and other auxiliary structure for the `ImageBuffer` type.
pub mod buffer {
    // Only those not exported at the top-level
    pub use crate::buffer_::{
        ConvertBuffer,
        EnumeratePixels,
        EnumeratePixelsMut,
        EnumerateRows,
        EnumerateRowsMut,
        Pixels,
        PixelsMut,
        Rows,
        RowsMut,
    };
}

// Math utils
pub mod math;

// Image processing functions
pub mod imageops;

// Io bindings
pub mod io;

// Buffer representations for ffi.
pub mod flat;

/// Encoding and decoding for various image file formats.
///
/// # Supported formats
///
/// | Format | Decoding | Encoding |
/// | ------ | -------- | -------- |
/// | PNG    | All supported color types | Same as decoding |
/// | JPEG   | Baseline and progressive | Baseline JPEG |
/// | GIF    | Yes | Yes |
/// | BMP    | Yes | RGB8, RGBA8, Gray8, GrayA8 |
/// | ICO    | Yes | Yes |
/// | TIFF   | Baseline(no fax support) + LZW + PackBits | RGB8, RGBA8, Gray8 |
/// | WebP   | Lossy(Luma channel only) | No |
/// | PNM    | PBM, PGM, PPM, standard PAM | Yes |
/// | DDS    | DXT1, DXT3, DXT5 | No |
/// | TGA    | Yes | RGB8, RGBA8, BGR8, BGRA8, Gray8, GrayA8 |
/// | farbfeld | Yes | Yes |
///
/// ## A note on format specific features
///
/// One of the main goals of `image` is stability, in runtime but also for programmers. This
/// ensures that performance as well as safety fixes reach a majority of its user base with little
/// effort. Re-exporting all details of its dependencies would run counter to this goal as it
/// linked _all_ major version bumps between them and `image`. As such, we are wary of exposing too
/// many details, or configuration options, that are not shared between different image formats.
///
/// Nevertheless, the advantage of precise control is hard to ignore. We will thus consider
/// _wrappers_, not direct re-exports, in either of the following cases:
///
/// 1. A standard specifies that configuration _x_ is required for decoders/encoders and there
///    exists an essentially canonical way to control it.
/// 2. At least two different implementations agree on some (sub-)set of features in practice.
/// 3. A technical argument including measurements of the performance, space benefits, or otherwise
///    objectively quantified benefits can be made, and the added interface is unlikely to require
///    breaking changes.
///
/// Features that fulfill two or more criteria are preferred.
///
/// Re-exports of dependencies that reach version `1` will be discussed when it happens.
pub mod codecs {
    #[cfg(feature = "avif")]
    pub mod avif;
    #[cfg(feature = "bmp")]
    pub mod bmp;
    #[cfg(feature = "dds")]
    pub mod dds;
    #[cfg(feature = "dxt")]
    pub mod dxt;
    #[cfg(feature = "farbfeld")]
    pub mod farbfeld;
    #[cfg(feature = "gif")]
    pub mod gif;
    #[cfg(feature = "hdr")]
    pub mod hdr;
    #[cfg(feature = "ico")]
    pub mod ico;
    #[cfg(feature = "jpeg")]
    pub mod jpeg;
    #[cfg(feature = "png")]
    pub mod png;
    #[cfg(feature = "pnm")]
    pub mod pnm;
    #[cfg(feature = "tga")]
    pub mod tga;
    #[cfg(feature = "tiff")]
    pub mod tiff;
    #[cfg(feature = "webp")]
    pub mod webp;
}

#[cfg(feature = "avif")]
#[deprecated = "Use codecs::avif instead"]
pub mod avif {
    //! Encoding of AVIF images.
    pub use crate::codecs::avif::AvifEncoder;
}
#[cfg(feature = "bmp")]
#[deprecated = "Use codecs::bmp instead"]
pub mod bmp {
    //! Decoding and Encoding of BMP Images
    #[allow(deprecated)]
    pub use crate::codecs::bmp::{BMPEncoder, BmpDecoder, BmpEncoder};
}
#[cfg(feature = "dds")]
#[deprecated = "Use codecs::dds instead"]
pub mod dds {
    //! Decoding of DDS images
    pub use crate::codecs::dds::DdsDecoder;
}
#[cfg(feature = "dxt")]
#[deprecated = "Use codecs:: instead"]
pub mod dxt {
    //! Decoding of DXT (S3TC) compression
    #[allow(deprecated)]
    pub use crate::codecs::dxt::{
        DXTEncoder, DXTReader, DXTVariant, DxtDecoder, DxtEncoder, DxtReader, DxtVariant,
    };
}
#[cfg(feature = "farbfeld")]
#[deprecated = "Use codecs::farbfeld instead"]
pub mod farbfeld {
    //! Decoding of farbfeld images
    pub use crate::codecs::farbfeld::{FarbfeldDecoder, FarbfeldEncoder, FarbfeldReader};
}
#[cfg(feature = "gif")]
#[deprecated = "Use codecs::gif instead"]
pub mod gif {
    //! Decoding of GIF Images
    #[allow(deprecated)]
    pub use crate::codecs::gif::{Encoder, GifDecoder, GifEncoder, GifReader};
}
#[cfg(feature = "hdr")]
#[deprecated = "Use codecs::hdr instead"]
pub mod hdr {
    //! Decoding of Radiance HDR Images
    #[allow(deprecated)]
    pub use crate::codecs::hdr::{
        read_raw_file, rgbe8, to_rgbe8, HDRAdapter, HDREncoder, HDRImageDecoderIterator,
        HDRMetadata, HdrAdapter, HdrDecoder, HdrEncoder, HdrImageDecoderIterator, HdrMetadata,
        HdrReader, RGBE8Pixel, Rgbe8Pixel, SIGNATURE,
    };
}
#[cfg(feature = "ico")]
#[deprecated = "Use codecs::ico instead"]
pub mod ico {
    //! Decoding and Encoding of ICO files
    #[allow(deprecated)]
    pub use crate::codecs::ico::{ICOEncoder, IcoDecoder, IcoEncoder};
}
#[cfg(feature = "jpeg")]
#[deprecated = "Use codecs::jpeg instead"]
pub mod jpeg {
    //! Decoding and Encoding of JPEG Images
    #[allow(deprecated)]
    pub use crate::codecs::jpeg::{
        JPEGEncoder, JpegDecoder, JpegEncoder, PixelDensity, PixelDensityUnit,
    };
}
#[cfg(feature = "png")]
#[deprecated = "Use codecs::png instead"]
pub mod png {
    //! Decoding and Encoding of PNG Images
    #[allow(deprecated)]
    pub use crate::codecs::png::{
        ApngDecoder, PNGEncoder, PNGReader, PngDecoder, PngEncoder, PngReader,
    };
}
#[cfg(feature = "pnm")]
#[deprecated = "Use codecs::pnm instead"]
pub mod pnm {
    //! Decoding and Encoding of netpbm image formats (pbm, pgm, ppm and pam)
    #[allow(deprecated)]
    pub use crate::codecs::pnm::{
        ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PNMEncoder, PNMHeader,
        PNMSubtype, PixmapHeader, PnmDecoder, PnmEncoder, PnmHeader, PnmSubtype, SampleEncoding,
    };
}
#[cfg(feature = "tga")]
#[deprecated = "Use codecs::tga instead"]
pub mod tga {
    //! Decoding and Encoding of TGA Images
    #[allow(deprecated)]
    pub use crate::codecs::tga::{TgaDecoder, TgaEncoder};
}
#[cfg(feature = "tiff")]
#[deprecated = "Use codecs::tiff instead"]
pub mod tiff {
    //! Decoding and Encoding of TIFF Images
    #[allow(deprecated)]
    pub use crate::codecs::tiff::{TiffDecoder, TiffEncoder, TiffReader};
}
#[cfg(feature = "webp")]
#[deprecated = "Use codecs::webp instead"]
pub mod webp {
    //! Decoding of WebP Images
    #[allow(deprecated)]
    pub use crate::codecs::webp::{vp8, WebPDecoder};
}

mod animation;
#[path = "buffer.rs"]
mod buffer_;
mod color;
mod dynimage;
mod image;
mod traits;
mod utils;

// Can't use the macro-call itself within the `doc` attribute. So force it to eval it as part of
// the macro invocation.
//
// The inspiration for the macro and implementation is from
// <https://github.com/GuillaumeGomez/doc-comment>
//
// MIT License
//
// Copyright (c) 2018 Guillaume Gomez
macro_rules! insert_as_doc {
    { $content:expr } => {
        #[doc = $content] extern { }
    }
}

// Provides the README.md as doc, to ensure the example works!
insert_as_doc!(include_str!("../README.md"));

// Copies data from `src` to `dst`
//
// Panics if the length of `dst` is less than the length of `src`.
#[inline]
fn copy_memory(src: &[u8], mut dst: &mut [u8]) {
    let len_src = src.len();
    assert!(dst.len() >= len_src);
    dst.write_all(src).unwrap();
}
<|endoftext|>


<commit_before>pub(crate) mod base;
pub mod mutators;
pub mod nav;
pub mod search;

use std::cell::UnsafeCell;
use std::error::Error;
use std::fmt;
use std::hash::Hash;
use std::ops::Deref;

use base::{EdgeId, RawEdge, RawVertex, VertexId};
use mutators::{MutEdge, MutNode};
use nav::{Edge, Node};
use symbol_map::indexing::{Indexing, Insertion};
use symbol_map::SymbolId;

/// A search graph.
///
/// Supports incremental rollout of game state topology and vertex
/// de-duplication with transposition tables. Limited support is provided for
/// deletion of components and compaction in memory after deletion.
///
/// - `T`: The type of game states. It is required to derive `Hash` and `Eq` to
///   so that it may be stored in a hashtable, where game states are looked up to
///   support de-duplication of game states. It is required to derive `Clone` to
///   accommodate a limitation of the `HashMap` interface.
/// - `S`: The type of graph vertex data.
/// - `A`: The type of graph edge data.
///
/// Vertices are addressed by content. To examine graph contents, obtain a node
/// handle with `get_node`. To modify graph contents, add new root vertices with
/// `add_node` and retrieve extant vertices with `get_node_mut`.
pub struct Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  /// Lookup table that maps from game states to `VertexId`.
  state_ids: symbol_map::indexing::HashIndexing<T, VertexId>,
  vertices: Vec<RawVertex<S>>, // Indexed by VertexId.
  arcs: Vec<RawEdge<A>>,       // Indexed by EdgeId.
}

impl<T, S, A> Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  /// Creates an empty `Graph` with no vertices or edges.
  pub fn new() -> Self {
    Graph {
      state_ids: Default::default(),
      vertices: Vec::new(),
      arcs: Vec::new(),
    }
  }

  /// Returns the vertex for the given `VertexId`.
  fn get_vertex(&self, state: VertexId) -> &RawVertex<S> {
    &self.vertices[state.as_usize()]
  }

  /// Returns the vertex for the given `VertexId`.
  fn get_vertex_mut(&mut self, state: VertexId) -> &mut RawVertex<S> {
    &mut self.vertices[state.as_usize()]
  }

  /// Returns the edge for the given `EdgeId`.
  fn get_arc(&self, arc: EdgeId) -> &RawEdge<A> {
    &self.arcs[arc.as_usize()]
  }

  /// Returns the edge for the given `EdgeId`.
  fn get_arc_mut(&mut self, arc: EdgeId) -> &mut RawEdge<A> {
    &mut self.arcs[arc.as_usize()]
  }

  /// Returns the game state associated with `id`.
  fn get_state(&self, id: VertexId) -> Option<&T> {
    self.state_ids.get_symbol(&id).as_ref().map(|x| x.data())
  }

  /// Adds a new vertex with the given data, returning a mutable reference to it.
  ///
  /// This method does not add incoming or outgoing edges (expanded or
  /// not). That must be done by calling `add_arc` with the new vertex
  /// `VertexId`.
  fn add_raw_vertex(&mut self, data: S) -> &mut RawVertex<S> {
    self.vertices.push(RawVertex {
      data: data,
      parents: Vec::new(),
      children: Vec::new(),
    });
    self.vertices.last_mut().unwrap()
  }

  /// Adds a new edge with the given data, source, and target. Returns the
  /// internal ID for the new edge.
  fn add_raw_edge(&mut self, data: A, source: VertexId, target: VertexId) -> EdgeId {
    let arc_id = EdgeId(self.arcs.len());
    self.get_vertex_mut(source).children.push(arc_id);
    self.get_vertex_mut(target).parents.push(arc_id);
    self.arcs.push(RawEdge {
      data: data,
      source: source,
      target: target,
    });
    arc_id
  }

  /// Gets a node handle for the given game state.
  ///
  /// If `state` does not correspond to a known game state, returns `None`.
  pub fn get_node<'s>(&'s self, state: &T) -> Option<Node<'s, T, S, A>> {
    match self.state_ids.get(state) {
      Some(symbol) => Some(Node::new(self, *symbol.id())),
      None => None,
    }
  }

  /// Gets a mutable node handle for the given game state.
  ///
  /// If `state` does not correspond to a known game state, returns `None`.
  pub fn get_node_mut<'s>(&'s mut self, state: &T) -> Option<MutNode<'s, T, S, A>> {
    match self.state_ids.get(state).map(|s| s.id().clone()) {
      Some(id) => Some(MutNode::new(self, id)),
      None => None,
    }
  }

  /// Adds a vertex (with no parents or children) for the given game state and
  /// data and returns a mutable handle for it.
  ///
  /// If `state` is already known, returns a mutable handle to that state,
  /// ignoring the `data` parameter. As a result, this method is guaranteed to
  /// return a handle for a root vertex only when `state` is a novel game
  /// state.
  pub fn add_node<'s>(&'s mut self, state: T, data: S) -> MutNode<'s, T, S, A> {
    let node_id = match self.state_ids.get_or_insert(state).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        self.add_raw_vertex(data);
        id
      }
    };
    MutNode::new(self, node_id)
  }

  /// Adds an edge from the vertex with state data `source` to the vertex with
  /// state data `dest`. If vertices are not found for `source` or `dest`,
  /// they are added, with the data provided by `source_data` and `dest_data`
  /// callbacks.
  ///
  /// The edge that is created will have the data `edge_data`. Returns a
  /// mutable edge handle for that edge.
  pub fn add_edge<'s, F, G>(
    &'s mut self,
    source: T,
    source_data: F,
    dest: T,
    dest_data: G,
    edge_data: A,
  ) -> MutEdge<'s, T, S, A>
  where
    F: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
    G: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
  {
    let source_id = match self.state_ids.get_or_insert(source).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        let data = source_data(Node::new(self, id));
        self.add_raw_vertex(data);
        id
      }
    };
    let dest_id = match self.state_ids.get_or_insert(dest).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        let data = dest_data(Node::new(self, id));
        self.add_raw_vertex(data);
        id
      }
    };
    let edge_id = self.add_raw_edge(edge_data, source_id, dest_id);
    MutEdge::new(self, edge_id)
  }

  /// Returns the number of vertices in the graph.
  pub fn vertex_count(&self) -> usize {
    // TODO: This is actually the number of vertices we have allocated.
    self.vertices.len()
  }

  /// Returns the number of edges in the graph.
  pub fn edge_count(&self) -> usize {
    // TODO: This is actually the number of edges we have allocated.
    self.arcs.len()
  }

  /// Deletes all graph components that are not reachable by traversal
  /// starting from each vertex corresponding to the game states in `roots`.
  ///
  /// Game states in `roots` which do not have a corresponding vertex are
  /// ignored.
  pub fn retain_reachable_from(&mut self, roots: &[&T]) {
    let mut root_ids = Vec::with_capacity(roots.len());
    for state in roots.iter() {
      if let Some(symbol) = self.state_ids.get(state) {
        root_ids.push(*symbol.id());
      }
    }
    self.retain_reachable_from_ids(&root_ids);
  }

  /// As `retain_reachable_from`, but working over raw `VertexId`s instead of
  /// root data.
  fn retain_reachable_from_ids(&mut self, root_ids: &[VertexId]) {
    mutators::mark_compact::Collector::retain_reachable(self, root_ids);
  }
}

/// Allows both read-only references into a `Graph` and operations that modify
/// the graph but do not invalidate family of types defined in the `nav`
/// module.
///
/// All methods on `Graph` that take a `&self` parameter may also be called on
/// an `AppendOnlyGraph`. The `add_node` and `add_edge` methods may also be
/// called, because they do not invalidate `Node`, `Edge`, or other such smart
/// pointers into the underlying graph. Unlike the analogous methods on `Graph`,
/// these methods return a read-only view of the graph topology, instead of
/// granting read-write access.
///
/// For example:
///
/// ```rust
/// # use search_graph::{AppendOnlyGraph, Graph};
/// # use search_graph::nav::{Node, Edge};
/// # fn main() {
/// let appendable: AppendOnlyGraph<u32, String, f32> = Graph::new().into();
/// let root1 = appendable.append_node(0, "data1".to_string());
/// // If appendable were a Graph, we could not call append_node while root1 is alive.
/// let root2 = appendable.append_node(1, "data2".to_string());
/// assert_eq!("data1", appendable.get_node(&0).unwrap().get_data());
/// assert!(root1.is_leaf());
/// let edge = appendable.append_edge(root1.clone(), root2.clone(), 3.3).unwrap();
/// assert_eq!(*edge.get_source().get_label(), 0);
/// assert_eq!(*edge.get_target().get_label(), 1);
/// assert!(!root1.is_leaf());
/// # }
/// ```
pub struct AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  graph: UnsafeCell<Graph<T, S, A>>,
}

#[derive(Debug)]
pub enum AppendEdgeError {
  GraphMismatch,
}

impl fmt::Display for AppendEdgeError {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{:?}", self)
  }
}

impl Error for AppendEdgeError {
  fn description(&self) -> &'static str {
    match *self {
      AppendEdgeError::GraphMismatch => "Underlying graph mismatch",
    }
  }
}

impl<T, S, A> AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  pub fn append_node<'s>(&'s self, state: T, data: S) -> Node<'s, T, S, A> {
    let graph: &mut Graph<T, S, A> = unsafe { &mut *self.graph.get() };
    graph.add_node(state, data).to_node()
  }

  pub fn append_edge<'s, 'a>(
    &'s self,
    source: Node<'a, T, S, A>,
    target: Node<'a, T, S, A>,
    edge_data: A,
  ) -> Result<Edge<'s, T, S, A>, AppendEdgeError> {
    if std::ptr::eq(source.graph, target.graph) {
      let graph: &mut Graph<T, S, A> = unsafe { &mut *self.graph.get() };
      let id = graph.add_raw_edge(edge_data, source.id, target.id);
      Ok(Edge { graph, id })
    } else {
      Err(AppendEdgeError::GraphMismatch)
    }
  }
}

impl<T, S, A> Deref for AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  type Target = Graph<T, S, A>;

  fn deref(&self) -> &Graph<T, S, A> {
    unsafe { &*self.graph.get() }
  }
}

impl<T, S, A> From<AppendOnlyGraph<T, S, A>> for Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  fn from(graph: AppendOnlyGraph<T, S, A>) -> Self {
    graph.graph.into_inner()
  }
}

impl<T, S, A> From<Graph<T, S, A>> for AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  fn from(graph: Graph<T, S, A>) -> Self {
    AppendOnlyGraph {
      graph: UnsafeCell::new(graph),
    }
  }
}

#[cfg(test)]
mod test {
  use crossbeam_utils::thread;
  use std::sync::Arc;

  type Graph = crate::Graph<&'static str, &'static str, &'static str>;

  #[test]
  fn send_to_thread_safe_ok() {
    let mut g = Graph::new();
    g.add_edge("root", |_| "root_data", "0", |_| "0_data", "root_0_data");
    g.add_edge("root", |_| "root_data", "1", |_| "1_data", "root_1_data");
    let graph = Arc::new(g);
    thread::scope(move |s| {
      let g = graph.clone();
      let t1 = s.spawn(move |_| g.get_node(&"root").map(|n| n.get_id()));
      let g = graph.clone();
      let t2 = s.spawn(move |_| g.get_node(&"1").map(|n| n.get_id()));
      match t1.join() {
        Ok(Some(id)) => assert_eq!(id, 0),
        _ => panic!(),
      }
      match t2.join() {
        Ok(Some(id)) => assert_eq!(id, 2),
        _ => panic!(),
      }
    })
    .unwrap();
  }

  #[test]
  fn sync_to_thread_ok() {
    let mut g = Graph::new();
    g.add_edge("root", |_| "root_data", "0", |_| "0_data", "root_0_data");
    g.add_edge("root", |_| "root_data", "1", |_| "1_data", "root_1_data");
    let g = &g;
    thread::scope(|s| {
      let t1 = s.spawn(move |_| g.get_node(&"root").map(|n| n.get_id()));
      let t2 = s.spawn(move |_| g.get_node(&"1").map(|n| n.get_id()));
      match t1.join() {
        Ok(Some(id)) => assert_eq!(id, 0),
        _ => panic!(),
      }
      match t2.join() {
        Ok(Some(id)) => assert_eq!(id, 2),
        _ => panic!(),
      }
    })
    .unwrap();
  }
}
<commit_msg>Improved error message<commit_after>pub(crate) mod base;
pub mod mutators;
pub mod nav;
pub mod search;

use std::cell::UnsafeCell;
use std::error::Error;
use std::fmt;
use std::hash::Hash;
use std::ops::Deref;

use base::{EdgeId, RawEdge, RawVertex, VertexId};
use mutators::{MutEdge, MutNode};
use nav::{Edge, Node};
use symbol_map::indexing::{Indexing, Insertion};
use symbol_map::SymbolId;

/// A search graph.
///
/// Supports incremental rollout of game state topology and vertex
/// de-duplication with transposition tables. Limited support is provided for
/// deletion of components and compaction in memory after deletion.
///
/// - `T`: The type of game states. It is required to derive `Hash` and `Eq` to
///   so that it may be stored in a hashtable, where game states are looked up to
///   support de-duplication of game states. It is required to derive `Clone` to
///   accommodate a limitation of the `HashMap` interface.
/// - `S`: The type of graph vertex data.
/// - `A`: The type of graph edge data.
///
/// Vertices are addressed by content. To examine graph contents, obtain a node
/// handle with `get_node`. To modify graph contents, add new root vertices with
/// `add_node` and retrieve extant vertices with `get_node_mut`.
pub struct Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  /// Lookup table that maps from game states to `VertexId`.
  state_ids: symbol_map::indexing::HashIndexing<T, VertexId>,
  vertices: Vec<RawVertex<S>>, // Indexed by VertexId.
  arcs: Vec<RawEdge<A>>,       // Indexed by EdgeId.
}

impl<T, S, A> Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  /// Creates an empty `Graph` with no vertices or edges.
  pub fn new() -> Self {
    Graph {
      state_ids: Default::default(),
      vertices: Vec::new(),
      arcs: Vec::new(),
    }
  }

  /// Returns the vertex for the given `VertexId`.
  fn get_vertex(&self, state: VertexId) -> &RawVertex<S> {
    &self.vertices[state.as_usize()]
  }

  /// Returns the vertex for the given `VertexId`.
  fn get_vertex_mut(&mut self, state: VertexId) -> &mut RawVertex<S> {
    &mut self.vertices[state.as_usize()]
  }

  /// Returns the edge for the given `EdgeId`.
  fn get_arc(&self, arc: EdgeId) -> &RawEdge<A> {
    &self.arcs[arc.as_usize()]
  }

  /// Returns the edge for the given `EdgeId`.
  fn get_arc_mut(&mut self, arc: EdgeId) -> &mut RawEdge<A> {
    &mut self.arcs[arc.as_usize()]
  }

  /// Returns the game state associated with `id`.
  fn get_state(&self, id: VertexId) -> Option<&T> {
    self.state_ids.get_symbol(&id).as_ref().map(|x| x.data())
  }

  /// Adds a new vertex with the given data, returning a mutable reference to it.
  ///
  /// This method does not add incoming or outgoing edges (expanded or
  /// not). That must be done by calling `add_arc` with the new vertex
  /// `VertexId`.
  fn add_raw_vertex(&mut self, data: S) -> &mut RawVertex<S> {
    self.vertices.push(RawVertex {
      data: data,
      parents: Vec::new(),
      children: Vec::new(),
    });
    self.vertices.last_mut().unwrap()
  }

  /// Adds a new edge with the given data, source, and target. Returns the
  /// internal ID for the new edge.
  fn add_raw_edge(&mut self, data: A, source: VertexId, target: VertexId) -> EdgeId {
    let arc_id = EdgeId(self.arcs.len());
    self.get_vertex_mut(source).children.push(arc_id);
    self.get_vertex_mut(target).parents.push(arc_id);
    self.arcs.push(RawEdge {
      data: data,
      source: source,
      target: target,
    });
    arc_id
  }

  /// Gets a node handle for the given game state.
  ///
  /// If `state` does not correspond to a known game state, returns `None`.
  pub fn get_node<'s>(&'s self, state: &T) -> Option<Node<'s, T, S, A>> {
    match self.state_ids.get(state) {
      Some(symbol) => Some(Node::new(self, *symbol.id())),
      None => None,
    }
  }

  /// Gets a mutable node handle for the given game state.
  ///
  /// If `state` does not correspond to a known game state, returns `None`.
  pub fn get_node_mut<'s>(&'s mut self, state: &T) -> Option<MutNode<'s, T, S, A>> {
    match self.state_ids.get(state).map(|s| s.id().clone()) {
      Some(id) => Some(MutNode::new(self, id)),
      None => None,
    }
  }

  /// Adds a vertex (with no parents or children) for the given game state and
  /// data and returns a mutable handle for it.
  ///
  /// If `state` is already known, returns a mutable handle to that state,
  /// ignoring the `data` parameter. As a result, this method is guaranteed to
  /// return a handle for a root vertex only when `state` is a novel game
  /// state.
  pub fn add_node<'s>(&'s mut self, state: T, data: S) -> MutNode<'s, T, S, A> {
    let node_id = match self.state_ids.get_or_insert(state).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        self.add_raw_vertex(data);
        id
      }
    };
    MutNode::new(self, node_id)
  }

  /// Adds an edge from the vertex with state data `source` to the vertex with
  /// state data `dest`. If vertices are not found for `source` or `dest`,
  /// they are added, with the data provided by `source_data` and `dest_data`
  /// callbacks.
  ///
  /// The edge that is created will have the data `edge_data`. Returns a
  /// mutable edge handle for that edge.
  pub fn add_edge<'s, F, G>(
    &'s mut self,
    source: T,
    source_data: F,
    dest: T,
    dest_data: G,
    edge_data: A,
  ) -> MutEdge<'s, T, S, A>
  where
    F: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
    G: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
  {
    let source_id = match self.state_ids.get_or_insert(source).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        let data = source_data(Node::new(self, id));
        self.add_raw_vertex(data);
        id
      }
    };
    let dest_id = match self.state_ids.get_or_insert(dest).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        let data = dest_data(Node::new(self, id));
        self.add_raw_vertex(data);
        id
      }
    };
    let edge_id = self.add_raw_edge(edge_data, source_id, dest_id);
    MutEdge::new(self, edge_id)
  }

  /// Returns the number of vertices in the graph.
  pub fn vertex_count(&self) -> usize {
    // TODO: This is actually the number of vertices we have allocated.
    self.vertices.len()
  }

  /// Returns the number of edges in the graph.
  pub fn edge_count(&self) -> usize {
    // TODO: This is actually the number of edges we have allocated.
    self.arcs.len()
  }

  /// Deletes all graph components that are not reachable by traversal
  /// starting from each vertex corresponding to the game states in `roots`.
  ///
  /// Game states in `roots` which do not have a corresponding vertex are
  /// ignored.
  pub fn retain_reachable_from(&mut self, roots: &[&T]) {
    let mut root_ids = Vec::with_capacity(roots.len());
    for state in roots.iter() {
      if let Some(symbol) = self.state_ids.get(state) {
        root_ids.push(*symbol.id());
      }
    }
    self.retain_reachable_from_ids(&root_ids);
  }

  /// As `retain_reachable_from`, but working over raw `VertexId`s instead of
  /// root data.
  fn retain_reachable_from_ids(&mut self, root_ids: &[VertexId]) {
    mutators::mark_compact::Collector::retain_reachable(self, root_ids);
  }
}

/// Allows both read-only references into a `Graph` and operations that modify
/// the graph but do not invalidate family of types defined in the `nav`
/// module.
///
/// All methods on `Graph` that take a `&self` parameter may also be called on
/// an `AppendOnlyGraph`. The `add_node` and `add_edge` methods may also be
/// called, because they do not invalidate `Node`, `Edge`, or other such smart
/// pointers into the underlying graph. Unlike the analogous methods on `Graph`,
/// these methods return a read-only view of the graph topology, instead of
/// granting read-write access.
///
/// For example:
///
/// ```rust
/// # use search_graph::{AppendOnlyGraph, Graph};
/// # use search_graph::nav::{Node, Edge};
/// # fn main() {
/// let appendable: AppendOnlyGraph<u32, String, f32> = Graph::new().into();
/// let root1 = appendable.append_node(0, "data1".to_string());
/// // If appendable were a Graph, we could not call append_node while root1 is alive.
/// let root2 = appendable.append_node(1, "data2".to_string());
/// assert_eq!("data1", appendable.get_node(&0).unwrap().get_data());
/// assert!(root1.is_leaf());
/// let edge = appendable.append_edge(root1.clone(), root2.clone(), 3.3).unwrap();
/// assert_eq!(*edge.get_source().get_label(), 0);
/// assert_eq!(*edge.get_target().get_label(), 1);
/// assert!(!root1.is_leaf());
/// # }
/// ```
pub struct AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  graph: UnsafeCell<Graph<T, S, A>>,
}

#[derive(Debug)]
pub enum AppendEdgeError {
  GraphMismatch,
}

impl fmt::Display for AppendEdgeError {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{:?}", self)
  }
}

impl Error for AppendEdgeError {
  fn description(&self) -> &'static str {
    match *self {
      AppendEdgeError::GraphMismatch => {
        "Underlying graph mismatch (cannot create an edge between vertices in two different graphs)"
      }
    }
  }
}

impl<T, S, A> AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  pub fn append_node<'s>(&'s self, state: T, data: S) -> Node<'s, T, S, A> {
    let graph: &mut Graph<T, S, A> = unsafe { &mut *self.graph.get() };
    graph.add_node(state, data).to_node()
  }

  pub fn append_edge<'s, 'a>(
    &'s self,
    source: Node<'a, T, S, A>,
    target: Node<'a, T, S, A>,
    edge_data: A,
  ) -> Result<Edge<'s, T, S, A>, AppendEdgeError> {
    if std::ptr::eq(source.graph, target.graph) {
      let graph: &mut Graph<T, S, A> = unsafe { &mut *self.graph.get() };
      let id = graph.add_raw_edge(edge_data, source.id, target.id);
      Ok(Edge { graph, id })
    } else {
      Err(AppendEdgeError::GraphMismatch)
    }
  }
}

impl<T, S, A> Deref for AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  type Target = Graph<T, S, A>;

  fn deref(&self) -> &Graph<T, S, A> {
    unsafe { &*self.graph.get() }
  }
}

impl<T, S, A> From<AppendOnlyGraph<T, S, A>> for Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  fn from(graph: AppendOnlyGraph<T, S, A>) -> Self {
    graph.graph.into_inner()
  }
}

impl<T, S, A> From<Graph<T, S, A>> for AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  fn from(graph: Graph<T, S, A>) -> Self {
    AppendOnlyGraph {
      graph: UnsafeCell::new(graph),
    }
  }
}

#[cfg(test)]
mod test {
  use crossbeam_utils::thread;
  use std::sync::Arc;

  type Graph = crate::Graph<&'static str, &'static str, &'static str>;

  #[test]
  fn send_to_thread_safe_ok() {
    let mut g = Graph::new();
    g.add_edge("root", |_| "root_data", "0", |_| "0_data", "root_0_data");
    g.add_edge("root", |_| "root_data", "1", |_| "1_data", "root_1_data");
    let graph = Arc::new(g);
    thread::scope(move |s| {
      let g = graph.clone();
      let t1 = s.spawn(move |_| g.get_node(&"root").map(|n| n.get_id()));
      let g = graph.clone();
      let t2 = s.spawn(move |_| g.get_node(&"1").map(|n| n.get_id()));
      match t1.join() {
        Ok(Some(id)) => assert_eq!(id, 0),
        _ => panic!(),
      }
      match t2.join() {
        Ok(Some(id)) => assert_eq!(id, 2),
        _ => panic!(),
      }
    })
    .unwrap();
  }

  #[test]
  fn sync_to_thread_ok() {
    let mut g = Graph::new();
    g.add_edge("root", |_| "root_data", "0", |_| "0_data", "root_0_data");
    g.add_edge("root", |_| "root_data", "1", |_| "1_data", "root_1_data");
    let g = &g;
    thread::scope(|s| {
      let t1 = s.spawn(move |_| g.get_node(&"root").map(|n| n.get_id()));
      let t2 = s.spawn(move |_| g.get_node(&"1").map(|n| n.get_id()));
      match t1.join() {
        Ok(Some(id)) => assert_eq!(id, 0),
        _ => panic!(),
      }
      match t2.join() {
        Ok(Some(id)) => assert_eq!(id, 2),
        _ => panic!(),
      }
    })
    .unwrap();
  }
}
<|endoftext|>


<commit_before>#![feature(trace_macros)]
#![feature(log_syntax)]

extern crate num;
extern crate rand;
extern crate rutorch;
#[macro_use]
extern crate modparse_derive;
#[macro_use]
extern crate derive_builder;

pub mod nn;
pub mod autograd;
pub mod optim;
pub mod utils;
pub mod tensor;
pub mod storage;
use std::rc::Rc;
use std::cell::RefCell;

// Mutable reference counted T
pub type RcMut<T> = Rc<RefCell<T>>;
// Nullable mutable reference counted T
pub type OptRcMut<T> = Option<RcMut<T>>;
/// Array index type
pub type Ix = usize;
/// Array index type (signed)
pub type Ixs = isize;

#[allow(non_snake_case)]
pub fn RcMutNew<T>(arg: T) -> RcMut<T> {
    Rc::new(RefCell::new(arg))
}

#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {}
}
<commit_msg>move up macros<commit_after>#![feature(trace_macros)]
#![feature(log_syntax)]

extern crate num;
extern crate rand;
extern crate rutorch;
#[macro_use]
extern crate modparse_derive;
#[macro_use]
extern crate derive_builder;
#[macro_use]
pub mod macros;

pub mod nn;
pub mod autograd;
pub mod optim;
pub mod utils;
pub mod tensor;
pub mod storage;
use std::rc::Rc;
use std::cell::RefCell;

// Mutable reference counted T
pub type RcMut<T> = Rc<RefCell<T>>;
// Nullable mutable reference counted T
pub type OptRcMut<T> = Option<RcMut<T>>;
/// Array index type
pub type Ix = usize;
/// Array index type (signed)
pub type Ixs = isize;

#[allow(non_snake_case)]
pub fn RcMutNew<T>(arg: T) -> RcMut<T> {
    Rc::new(RefCell::new(arg))
}

#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate route_recognizer;

use hyper::header::Headers;
use hyper::method::Method;
use hyper::server::Handler as HyperHandler;
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

use route_recognizer::{Match, Params, Router};

#[macro_export]
macro_rules! create_router {
    ( $( $path:expr => $( $method:ident ),+ => $handler:expr ),+, ) => {{
        let mut router = $crate::HyperRouter::new();

        $(
            let mut entry = $crate::RouteEntry::with_handler($handler);
            $(
                entry.add_method($crate::MethodRoutes::$method);
            )+

            router.add_path_entry($path, entry);
        )+

        router
    }};
}

fn method_to_bit(method: &Method) -> u8 {
    use hyper::method::Method::*;
    let exp = match *method {
        Options => 0,
        Get | Head => 1,
        Post => 2,
        Put => 3,
        Delete => 4,
        Connect => 5,
        Patch => 6,
        Trace | Extension(_) => 7,
    };

    1u8 << exp
}

fn method_route_to_bit(method: MethodRoutes) -> u8 {
    use MethodRoutes::*;
    let exp = match method {
        Options => 0,
        Get => 1,
        Post => 2,
        Put => 3,
        Delete => 4,
        Connect => 5,
        Patch => 6,
        Other => 7,
    };

    1u8 << exp
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MethodRoutes {
    Options,
    Get,
    Post,
    Put,
    Delete,
    Connect,
    Patch,
    Other,
}

#[derive(Debug)]
pub struct RouteEntry<H> {
    accepted_methods: u8,
    handler: H,
}

impl<H> RouteEntry<H> {
    pub fn with_handler(handler: H) -> RouteEntry<H> {
        RouteEntry {
            accepted_methods: 0,
            handler: handler,
        }
    }

    pub fn add_method(&mut self, method: MethodRoutes) {
        self.accepted_methods |= method_route_to_bit(method);
    }

    pub fn add_methods(&mut self, methods: &[MethodRoutes]) {
        for method in methods {
            self.accepted_methods |= method_route_to_bit(*method);
        }
    }

    pub fn add_all_methods(&mut self) {
        self.accepted_methods = !0u8;
    }

    pub fn accepts_method(&self, method: &Method) -> bool {
        (self.accepted_methods & method_to_bit(method)) > 0
    }

    pub fn handler(&self) -> &H {
        &self.handler
    }
}

pub trait RouteHandler: Sync + Send {
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>);

    fn check_continue(&self, _: Params, _: (&Method, &RequestUri, &Headers)) -> StatusCode {
        StatusCode::Continue
    }
}

impl RouteHandler for Box<RouteHandler> {
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self.as_ref().handle(params, req, res)
    }

    fn check_continue(&self, params: Params, t: (&Method, &RequestUri, &Headers)) -> StatusCode {
        self.as_ref().check_continue(params, t)
    }
}

impl RouteHandler for HyperHandler {
    fn handle<'a, 'k>(&'a self, _: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self.handle(req, res)
    }

    fn check_continue(&self, _: Params, tuple: (&Method, &RequestUri, &Headers)) -> StatusCode {
        self.check_continue(tuple)
    }
}

impl<F> RouteHandler for F
    where F: Fn(Params, Request, Response),
          F: Sync + Send
{
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self(params, req, res)
    }
}

pub struct HyperRouter<H> {
    path_router: Router<RouteEntry<H>>,
    url_router: Router<RouteEntry<H>>,
    authority_router: Router<RouteEntry<H>>,
    server_wide: Option<RouteEntry<H>>,
}

impl<H> HyperRouter<H> {
    pub fn new() -> HyperRouter<H> {
        HyperRouter {
            path_router: Router::new(),
            url_router: Router::new(),
            authority_router: Router::new(),
            server_wide: None,
        }
    }

    pub fn add_path_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_url_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_authority_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_server_wide_entry(&mut self, entry: RouteEntry<H>) {
        self.server_wide = Some(entry);
    }

    pub fn get_match(&self, method: &Method, uri: &RequestUri) -> Option<Match<&RouteEntry<H>>> {
        use hyper::uri::RequestUri::*;

        let m = match *uri {
            AbsolutePath(ref path) => self.path_router.recognize(&path).ok(),
            AbsoluteUri(ref url) => self.url_router.recognize(url.as_str()).ok(),
            Authority(ref authority) => self.authority_router.recognize(&authority).ok(),
            Star => {
                self.server_wide.as_ref().map(|handler| {
                    Match {
                        handler: handler,
                        params: Params::new(),
                    }
                })
            }
        };

        if let Some(mat) = m {
            if mat.handler.accepts_method(method) {
                Some(mat)
            } else {
                None
            }
        } else {
            None
        }
    }
}

impl<H> HyperHandler for HyperRouter<H>
    where H: AsRef<RouteHandler> + Send + Sync
{
    fn handle<'a, 'k>(&'a self, req: Request<'a, 'k>, mut res: Response<'a>) {
        if let Some(matches) = self.get_match(&req.method, &req.uri) {
            let Match { handler, params } = matches;
            handler.handler.as_ref().handle(params, req, res);
        } else {
            *res.status_mut() = StatusCode::NotFound;
        }
    }

    fn check_continue(&self, tuple: (&Method, &RequestUri, &Headers)) -> StatusCode {
        if let Some(matches) = self.get_match(tuple.0, tuple.1) {
            let Match { handler, params } = matches;
            handler.handler.as_ref().check_continue(params, tuple)
        } else {
            StatusCode::Continue
        }
    }
}

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

    use hyper::method::Method;
    use hyper::uri::RequestUri;

    #[test]
    fn simple_test() {
        let mut entry = RouteEntry::with_handler(0u8);
        entry.add_method(MethodRoutes::Get);
        let mut router = HyperRouter::new();
        router.add_path_entry("/test/", entry);

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test2/")));
        assert!(res.is_none());

        let res = router.get_match(&Method::Post,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert!(res.is_none());
    }

    #[test]
    fn multi_method_test() {
        let mut entry = RouteEntry::with_handler(0u8);
        entry.add_method(MethodRoutes::Get);
        entry.add_method(MethodRoutes::Put);
        let mut router = HyperRouter::new();
        router.add_path_entry("/test/", entry);

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Put,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Post,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert!(res.is_none());
    }

    #[test]
    fn create_router_test() {
        let router = create_router! {
            "/test/" => Get, Put => 0u8,
            "/test2/:id" => Delete => 1u8,
        };

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Put,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Delete,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert!(res.is_none());

        let res = router.get_match(&Method::Delete,
                                   &RequestUri::AbsolutePath(String::from("/test2/test")));
        assert_eq!(res.as_ref().unwrap().handler.handler, 1u8);
        assert_eq!(res.unwrap().params["id"], "test");
    }
}
<commit_msg>Reexport Match and Params<commit_after>extern crate hyper;
extern crate route_recognizer;

use hyper::header::Headers;
use hyper::method::Method;
use hyper::server::Handler as HyperHandler;
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

use route_recognizer::Router;

pub use route_recognizer::{Match, Params};

#[macro_export]
macro_rules! create_router {
    ( $( $path:expr => $( $method:ident ),+ => $handler:expr ),+, ) => {{
        let mut router = $crate::HyperRouter::new();

        $(
            let mut entry = $crate::RouteEntry::with_handler($handler);
            $(
                entry.add_method($crate::MethodRoutes::$method);
            )+

            router.add_path_entry($path, entry);
        )+

        router
    }};
}

fn method_to_bit(method: &Method) -> u8 {
    use hyper::method::Method::*;
    let exp = match *method {
        Options => 0,
        Get | Head => 1,
        Post => 2,
        Put => 3,
        Delete => 4,
        Connect => 5,
        Patch => 6,
        Trace | Extension(_) => 7,
    };

    1u8 << exp
}

fn method_route_to_bit(method: MethodRoutes) -> u8 {
    use MethodRoutes::*;
    let exp = match method {
        Options => 0,
        Get => 1,
        Post => 2,
        Put => 3,
        Delete => 4,
        Connect => 5,
        Patch => 6,
        Other => 7,
    };

    1u8 << exp
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MethodRoutes {
    Options,
    Get,
    Post,
    Put,
    Delete,
    Connect,
    Patch,
    Other,
}

#[derive(Debug)]
pub struct RouteEntry<H> {
    accepted_methods: u8,
    handler: H,
}

impl<H> RouteEntry<H> {
    pub fn with_handler(handler: H) -> RouteEntry<H> {
        RouteEntry {
            accepted_methods: 0,
            handler: handler,
        }
    }

    pub fn add_method(&mut self, method: MethodRoutes) {
        self.accepted_methods |= method_route_to_bit(method);
    }

    pub fn add_methods(&mut self, methods: &[MethodRoutes]) {
        for method in methods {
            self.accepted_methods |= method_route_to_bit(*method);
        }
    }

    pub fn add_all_methods(&mut self) {
        self.accepted_methods = !0u8;
    }

    pub fn accepts_method(&self, method: &Method) -> bool {
        (self.accepted_methods & method_to_bit(method)) > 0
    }

    pub fn handler(&self) -> &H {
        &self.handler
    }
}

pub trait RouteHandler: Sync + Send {
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>);

    fn check_continue(&self, _: Params, _: (&Method, &RequestUri, &Headers)) -> StatusCode {
        StatusCode::Continue
    }
}

impl RouteHandler for Box<RouteHandler> {
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self.as_ref().handle(params, req, res)
    }

    fn check_continue(&self, params: Params, t: (&Method, &RequestUri, &Headers)) -> StatusCode {
        self.as_ref().check_continue(params, t)
    }
}

impl RouteHandler for HyperHandler {
    fn handle<'a, 'k>(&'a self, _: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self.handle(req, res)
    }

    fn check_continue(&self, _: Params, tuple: (&Method, &RequestUri, &Headers)) -> StatusCode {
        self.check_continue(tuple)
    }
}

impl<F> RouteHandler for F
    where F: Fn(Params, Request, Response),
          F: Sync + Send
{
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self(params, req, res)
    }
}

pub struct HyperRouter<H> {
    path_router: Router<RouteEntry<H>>,
    url_router: Router<RouteEntry<H>>,
    authority_router: Router<RouteEntry<H>>,
    server_wide: Option<RouteEntry<H>>,
}

impl<H> HyperRouter<H> {
    pub fn new() -> HyperRouter<H> {
        HyperRouter {
            path_router: Router::new(),
            url_router: Router::new(),
            authority_router: Router::new(),
            server_wide: None,
        }
    }

    pub fn add_path_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_url_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_authority_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_server_wide_entry(&mut self, entry: RouteEntry<H>) {
        self.server_wide = Some(entry);
    }

    pub fn get_match(&self, method: &Method, uri: &RequestUri) -> Option<Match<&RouteEntry<H>>> {
        use hyper::uri::RequestUri::*;

        let m = match *uri {
            AbsolutePath(ref path) => self.path_router.recognize(&path).ok(),
            AbsoluteUri(ref url) => self.url_router.recognize(url.as_str()).ok(),
            Authority(ref authority) => self.authority_router.recognize(&authority).ok(),
            Star => {
                self.server_wide.as_ref().map(|handler| {
                    Match {
                        handler: handler,
                        params: Params::new(),
                    }
                })
            }
        };

        if let Some(mat) = m {
            if mat.handler.accepts_method(method) {
                Some(mat)
            } else {
                None
            }
        } else {
            None
        }
    }
}

impl<H> HyperHandler for HyperRouter<H>
    where H: AsRef<RouteHandler> + Send + Sync
{
    fn handle<'a, 'k>(&'a self, req: Request<'a, 'k>, mut res: Response<'a>) {
        if let Some(matches) = self.get_match(&req.method, &req.uri) {
            let Match { handler, params } = matches;
            handler.handler.as_ref().handle(params, req, res);
        } else {
            *res.status_mut() = StatusCode::NotFound;
        }
    }

    fn check_continue(&self, tuple: (&Method, &RequestUri, &Headers)) -> StatusCode {
        if let Some(matches) = self.get_match(tuple.0, tuple.1) {
            let Match { handler, params } = matches;
            handler.handler.as_ref().check_continue(params, tuple)
        } else {
            StatusCode::Continue
        }
    }
}

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

    use hyper::method::Method;
    use hyper::uri::RequestUri;

    #[test]
    fn simple_test() {
        let mut entry = RouteEntry::with_handler(0u8);
        entry.add_method(MethodRoutes::Get);
        let mut router = HyperRouter::new();
        router.add_path_entry("/test/", entry);

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test2/")));
        assert!(res.is_none());

        let res = router.get_match(&Method::Post,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert!(res.is_none());
    }

    #[test]
    fn multi_method_test() {
        let mut entry = RouteEntry::with_handler(0u8);
        entry.add_method(MethodRoutes::Get);
        entry.add_method(MethodRoutes::Put);
        let mut router = HyperRouter::new();
        router.add_path_entry("/test/", entry);

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Put,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Post,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert!(res.is_none());
    }

    #[test]
    fn create_router_test() {
        let router = create_router! {
            "/test/" => Get, Put => 0u8,
            "/test2/:id" => Delete => 1u8,
        };

        let res = router.get_match(&Method::Get,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Put,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert_eq!(res.unwrap().handler.handler, 0u8);

        let res = router.get_match(&Method::Delete,
                                   &RequestUri::AbsolutePath(String::from("/test/")));
        assert!(res.is_none());

        let res = router.get_match(&Method::Delete,
                                   &RequestUri::AbsolutePath(String::from("/test2/test")));
        assert_eq!(res.as_ref().unwrap().handler.handler, 1u8);
        assert_eq!(res.unwrap().params["id"], "test");
    }
}
<|endoftext|>