<commit_before>#[test]
fn it_works() {
}
<commit_msg>Some heap data structures.<commit_after>#![feature(default_type_params)]
#![feature(macro_rules)]

/*use std::mem;
use std::ptr::RawPtr;
use std::raw::Repr;
use std::raw::Slice as RawSlice;
use std::uint;*/

#[deriving(Show)]
//#[repr(C)]
pub struct Oid(u32);

#[deriving(Show)]
//#[repr(C)]
pub struct TransactionId(u32);

#[deriving(Show)]
//#[repr(C)]
pub struct CommandId(u32);

#[deriving(Show)]
//#[repr(C)]
pub struct BlockNumber(u32);

#[deriving(Show)]
//#[repr(C)]
pub struct BlockIdData {
    bi_hi: u16,
    bi_lo: u16,
}

#[deriving(Show)]
//#[repr(C)]
pub struct OffsetNumber(u16);

#[deriving(Show)]
//#[repr(C,packed)]
pub struct ItemPointerData {
    ip_blkid: BlockIdData,
    ip_posid: OffsetNumber,
}

#[deriving(Show)]
//#[repr(C,packed)]
#[repr(packed)]
pub struct HeapTupleFields {
    t_xmin: TransactionId, // inserting xact ID
    t_xmax: TransactionId, // deleting or locking xact ID
    t_cid: CommandId, // inserting or deleting command ID, or both
}

#[deriving(Show)]
//#[repr(C,packed)]
pub struct NormalTupleHeaderData {
    t_heap: HeapTupleFields,
    t_ctid: ItemPointerData, // current t_ctid of this or newer tuple
}

#[deriving(Show)]
//#[repr(C,packed)]
pub struct MinimalTupleHeaderData; // unit struct

#[deriving(Show)]
#[repr(C)]
pub struct HeapTupleHeaderData<T> {
    t_data_: T,
    // ^ - 18 bytes (normally) - ^
    t_infomask2: u16, // number of attributes + various flags
    t_infomask: u16, // various flag bits, see below
    t_hoff: u8, // sizeof header incl. bitmap, padding
    // ^ - 5 bytes, 23 bytes total (normally) - ^
    t_bits_: [u8, .. 1] // bitmap of NULLs -- VARIABLE LENGTH
    // MORE DATA FOLLOWS AT END OF STRUCT
}

impl<T> Deref<T> for HeapTupleHeaderData<T> {
    #[inline]
    fn deref(&self) -> &T { &self.t_data_ }
}

impl<T> DerefMut<T> for HeapTupleHeaderData<T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut T { &mut self.t_data_ }
}

/*#[deriving(Show)]
pub struct BitMap {
    t_bits: &[u8],
}*/

/*impl<T> HeapTupleHeaderData<T> {
    #[inline]
    fn t_bits_len(&self) -> uint {
        self.len
    }

    pub fn t_bits(&self) -> BitMap {
        let len =
        unsafe { ::std::mem::transmute(self.t_bits_.repr().data
    }
}*/

pub struct HeapTupleHeader<T, U> {
    t_len: u32,
    t_header_: T,
    t_data: U,
}

pub struct HeapTupleTemp;

pub struct HeapTupleDisk {
    t_self: ItemPointerData, // SelfItemPointer
    t_table_oid: Oid, // table the tuple came from
}

impl<T, U> Deref<T> for HeapTupleHeader<T, U> {
    fn deref(&self) -> &T {
        &self.t_header_
    }
}

impl<T, U> DerefMut<T> for HeapTupleHeader<T, U> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.t_header_
    }
}

pub type HeapTupleDirectData<'a, T, U = NormalTupleHeaderData> = HeapTupleHeader<T, &'a HeapTupleHeaderData<U>>;

pub type HeapTupleContiguousData<T, U = NormalTupleHeaderData> = HeapTupleHeader<T, HeapTupleHeaderData<U>>;

/*#[repr(C,packed)]
pub struct HeapTupleHeaderInfo<Sized? T> {
    t_infomask2: u16, // number of attributes + various flags
    t_infomask: u16, // various flag bits, see below
    t_hoff: u8, // sizeof header incl. bitmap, padding
    // ^ - 5 bytes - ^
    t_bits: T // bitmap of NULLs -- VARIABLE LENGTH
}

#[repr(C)]
pub struct HeapTupleHeaderData<Sized? T> {
    t_heap: HeapTupleFields,
    t_ctid: ItemPointerData, // current t_ctid of this or newer tuple
    // ^ - 18 bytes - ^
    // Fields below here must match MinimalTupleData!
    t_info: HeapTupleHeaderInfo<T>,
}

impl Deref<HeapTupleHeaderInfo<[u8]>> for HeapTupleHeaderData<[u8]> {
    fn deref(&self) -> &HeapTupleHeaderInfo<[u8]> {
        &self.t_info
    }
}

/*impl DerefMut<HeapTupleHeaderInfo> for HeapTupleHeaderData {
    pub fn deref_mut(&mut self) -> &mut HeapTupleHeaderInfo {
        &mut self.t_info
    }
}*/

/*impl Repr<HeapTupleHeaderData> for [T] {
}*/*/

pub const MAXIMUM_ALIGNOF: uint = 8;

macro_rules! offset_of(($ty:ty,$field:ident) => {
    unsafe {
        //use std::raw::Repr;
        //use std::ptr::RawPtr;
        //let data = ::std::mem::transmute::<[u8], $ty>(::std::mem::uninitialized());
        //let data = ::std::mem::uninitialized::<$ty>();
        let data = ::std::mem::uninitialized::<$ty>();
        //let data = 0 as *const $ty;

        //let data = ::std::mem::zeroed::<*const $ty>();
        //let offset = (&(*data).$field as *const _).to_uint();
        //let offset = (&(*data).$field as *const _) as uint;//.to_uint();
        //mem::forget(data);
        //let offset = (&(*data).$field as *const _ as uint) - (&data as *const _ as uint);//.to_uint();
        let offset = (&data.$field as *const _ as uint) - (&data as *const _ as uint);//.to_uint();
        mem::forget(data);
        offset
    }
})

// (offsetof(HeapTupleHeaderData, t_infomask2) - sizeof(uint32)) % MAXIMUM_ALIGNOF
pub const MINIMAL_TUPLE_PADDING: uint = 6;

/*#[repr(C)]
pub struct MinimalTupleData<Sized? T> {
    t_len: u32, // actual length of minimal tuple
    mt_padding: [u8, .. MINIMAL_TUPLE_PADDING],
    // ^ - 18 bytes - ^
    // Fields below here must match HeapTupleHeaderData!
    t_info: HeapTupleHeaderInfo<T>,
}

impl Deref<HeapTupleHeaderInfo<[u8]>> for MinimalTupleData<[u8]> {
    fn deref(&self) -> &HeapTupleHeaderInfo<[u8]> {
        &self.t_info
    }
}

/*pub struct Version {
    version: uint,
}

pub struct Transaction {
    version: Version,
}

pub const BUFFER_SIZE: uint = 512;

struct Buffer {
    buffer: Arc<RwLock<[u8, .. BUFFER_SIZE]>>,
}

struct Page {
    : UnsafeCell<T>,
}

struct Database {
    pages: Pages,
}

pub struct TransactionManager {
    transactions: *T,
    database: Database,
}*/*/

#[cfg(test)]
mod tests {
    use std::mem;
    //use std::raw::Repr;
    use std::u32;
    use super::{
        HeapTupleContiguousData,
        HeapTupleDirectData,
        HeapTupleDisk,
        //HeapTupleHeader,
        HeapTupleHeaderData,
        //HeapTupleHeaderInfo,
        HeapTupleTemp,
        //MinimalTupleData,
        MinimalTupleHeaderData,
        NormalTupleHeaderData,
    };

    #[test]
    fn maximum_alignof() {
        assert_eq!(mem::align_of::<uint>(), super::MAXIMUM_ALIGNOF);
    }

    #[test]
    // (offsetof(HeapTupleHeaderData, t_infomask2) - sizeof(uint32)) % MAXIMUM_ALIGNOF
    fn minimal_tuple_padding() {
        /*let offset = unsafe {
            let data = HeapTupleHeaderData {
                t_heap: mem::uninitialized(),
                t_ctid: mem::uninitialized(),
                t_info: HeapTupleHeaderInfo {
                    t_infomask2: mem::uninitialized(),
                    t_infomask: mem::uninitialized(),
                    t_hoff: mem::uninitialized(),
                    t_bits: [0u8, .. 0],
                }
            };
            let HeapTupleHeaderData {
                t_heap: t_heap,
                t_ctid: t_ctid,
                t_info: /*HeapTupleHeaderInfo {
                    t_infomask2: t_infomask2,
                    t_infomask: t_infomask,
                    t_hoff: t_hoff,
                    t_bits: ref t_bits,
                }*/ref t_info
            } = data;
            /*let HeapTupleHeaderInfo {
                t_infomask2: t_infomask2,
                t_infomask: t_infomask,
                t_hoff: t_hoff,
                t_bits: ref t_bits,
            } = t_info;*/
            //let t_bits: &[u8] = &*t_bits;
            /*let t_info: &HeapTupleHeaderInfo<[u8]> = &HeapTupleHeaderInfo {
                t_infomask2: t_infomask2,
                t_infomask: t_infomask,
                t_hoff: t_hoff,
                t_bits: *t_bits,
            };*/

            let data: &HeapTupleHeaderData<[u8]> = &HeapTupleHeaderData {
                t_heap: t_heap,
                t_ctid: t_ctid,
                t_info: *t_info,
            };
            println!("{}", data.t_bits.len());
            //let data = mem::transmute::<_, &HeapTupleHeaderData<[u8]>>(&data);
            //let offset = (&(*data).$field as *const _).to_uint();
            //let offset = (&data.t_info as *const _ as uint) - (data as *const _ as uint);
            //let offset = (&data.t_info as *const _ as uint) - (&data as *const _ as uint);
            //mem::forget(data);
            //offset
            0
        };*/

        //let offset = offset_of!(HeapTupleHeaderData<MinimalTupleHeaderData>, t_infomask2);
        //println!("{} {}", offset, mem::size_of::<HeapTupleHeaderData<MinimalTupleHeaderData>>());
        let offset = offset_of!(HeapTupleContiguousData<HeapTupleTemp, MinimalTupleHeaderData>, t_data);
        println!("{} {}", offset, mem::size_of::<HeapTupleContiguousData<HeapTupleTemp, MinimalTupleHeaderData>>());
        let offset = offset_of!(HeapTupleDirectData<HeapTupleTemp>, t_data);
        println!("{} {}", offset, mem::size_of::<HeapTupleDirectData<HeapTupleTemp>>());
        let offset = offset_of!(HeapTupleDirectData<HeapTupleDisk>, t_data);
        println!("{} {}", offset, mem::size_of::<HeapTupleDirectData<HeapTupleDisk>>());
        let offset = offset_of!(HeapTupleContiguousData<HeapTupleDisk, MinimalTupleHeaderData>, t_data);
        println!("{} {}", offset, mem::size_of::<HeapTupleContiguousData<HeapTupleDisk, MinimalTupleHeaderData>>());
        let offset = offset_of!(HeapTupleContiguousData<HeapTupleTemp>, t_data);
        println!("{} {}", offset, mem::size_of::<HeapTupleContiguousData<HeapTupleTemp>>());
        let offset = offset_of!(HeapTupleContiguousData<HeapTupleDisk>, t_data);
        println!("{} {}", offset, mem::size_of::<HeapTupleContiguousData<HeapTupleDisk>>());

        let offset = offset_of!(HeapTupleHeaderData<NormalTupleHeaderData>, t_infomask2);
        //println!("{} {}", offset, mem::size_of::<HeapTupleHeaderData<NormalTupleHeaderData>>());
        let minimal_tuple_padding = (offset - u32::BYTES) % super::MAXIMUM_ALIGNOF;
        assert_eq!(minimal_tuple_padding, super::MINIMAL_TUPLE_PADDING);

        /*let offset = offset_of!(HeapTupleHeaderData<[u8, ..0]>, t_info);
        let minimal_tuple_padding = (offset - u32::BYTES) % super::MAXIMUM_ALIGNOF;
        assert_eq!(minimal_tuple_padding, super::MINIMAL_TUPLE_PADDING);
        let offset = offset_of!(MinimalTupleData<[u8, ..0]>, t_info);
        assert_eq!(minimal_tuple_padding, super::MINIMAL_TUPLE_PADDING);*/
    }
}
<|endoftext|>


<commit_before>//! ## Defining procedural macros
//!
//! Two crates are required to define a macro.
//!
//! ### The declaration crate
//!
//! This crate is allowed to contain other public things if you need, for example
//! traits or functions or ordinary macros.
//!
//! https://github.com/dtolnay/proc-macro-hack/tree/master/demo-hack
//!
//! ```rust,ignore
//! #[macro_use]
//! extern crate proc_macro_hack;
//!
//! #[allow(unused_imports)]
//! #[macro_use]
//! extern crate demo_hack_impl;
//! #[doc(hidden)]
//! pub use demo_hack_impl::*;
//!
//! proc_macro_expr_decl! {
//!     /// Add one to an expression.
//!     add_one! => add_one_impl
//! }
//!
//! proc_macro_item_decl! {
//!     /// A function that always returns 2.
//!     two_fn! => two_fn_impl
//! }
//! ```
//!
//! ### The implementation crate
//!
//! This crate must contain nothing but procedural macros. Private helper functions
//! and private modules are fine but nothing can be public.
//!
//! https://github.com/dtolnay/proc-macro-hack/tree/master/demo-hack-impl
//!
//! ```rust,ignore
//! #[macro_use]
//! extern crate proc_macro_hack;
//!
//! proc_macro_expr_impl! {
//!     /// Add one to an expression.
//!     pub fn add_one_impl(input: &str) -> String {
//!         format!("1 + {}", input)
//!     }
//! }
//!
//! proc_macro_item_impl! {
//!     /// A function that always returns 2.
//!     pub fn two_fn_impl(input: &str) -> String {
//!         format!("fn {}() -> u8 {{ 2 }}", input)
//!     }
//! }
//! ```
//!
//! Both crates depend on `proc-macro-hack`:
//!
//! ```toml
//! [dependencies]
//! proc-macro-hack = "0.3"
//! ```
//!
//! Additionally, your implementation crate (but not your declaration crate) is a
//! proc macro:
//!
//! ```toml
//! [lib]
//! proc-macro = true
//! ```
//!
//! ## Using procedural macros
//!
//! Users of your crate depend on your declaration crate (not your implementation
//! crate), then use your procedural macros as though it were magic. They even get
//! reasonable error messages if your procedural macro panics.
//!
//! https://github.com/dtolnay/proc-macro-hack/tree/master/example
//!
//! ```rust,ignore
//! #[macro_use]
//! extern crate demo_hack;
//!
//! two_fn!(two);
//!
//! fn main() {
//!     let x = two();
//!     let nine = add_one!(x) + add_one!(2 + 3);
//!     println!("nine = {}", nine);
//! }
//! ```
//!
//! ---
//!
//! # Expansion of expression macros
//!
//! ```rust,ignore
//! m!(ARGS)
//! ```
//!
//! ... expands to ...
//!
//! ```rust,ignore
//! {
//!     #[derive(m_impl)]
//!     #[allow(unused)]
//!     enum ProcMacroHack {
//!         Input = (stringify!(ARGS), 0).1,
//!     }
//!     proc_macro_call!()
//! }
//! ```
//!
//! ... expands to ...
//!
//! ```rust,ignore
//! {
//!     macro_rules! proc_macro_call {
//!         () => { RESULT }
//!     }
//!     proc_macro_call!()
//! }
//! ```
//!
//! ... expands to ...
//!
//! ```rust,ignore
//! {
//!     RESULT
//! }
//! ```
//!
//! # Expansion of item macros
//!
//! ```rust,ignore
//! m!(ARGS);
//! ```
//!
//! ... expands to ...
//!
//! ```rust,ignore
//! #[derive(m_impl)]
//! #[allow(unused)]
//! enum ProcMacroHack {
//!     Input = (stringify!(ARGS), 0).1,
//! }
//! ```
//!
//! ... expands to ...
//!
//! ```rust,ignore
//! RESULT
//! ```

#[cfg(feature = "proc_macro")]
extern crate proc_macro;

// Allow the "unused" #[macro_use] because there is a different un-ignorable
// warning otherwise:
//
//    proc macro crates and `#[no_link]` crates have no effect without `#[macro_use]`
#[allow(unused_imports)]
#[macro_use]
extern crate proc_macro_hack_impl;
#[doc(hidden)]
pub use proc_macro_hack_impl::*;

#[cfg(feature = "proc_macro")]
#[doc(hidden)]
pub use proc_macro::TokenStream;

#[cfg(feature = "proc_macro")]
#[doc(hidden)]
#[macro_export]
macro_rules! proc_macro_tokenstream {
    () => {
        $crate::TokenStream
    }
}

#[cfg(not(feature = "proc_macro"))]
#[doc(hidden)]
#[macro_export]
macro_rules! proc_macro_tokenstream {
    () => {
        ::proc_macro::TokenStream
    }
}

#[macro_export]
macro_rules! proc_macro_expr_decl {
    (#[$attr:meta] $($rest:tt)+) => {
        proc_macro_expr_decl_helper!((#[$attr]) $($rest)+);
    };
    ($name:ident ! => $name_impl:ident) => {
        proc_macro_expr_decl_helper!(() $name ! => $name_impl);
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! proc_macro_expr_decl_helper {
    (($($attrs:tt)*) #[$first:meta] $($rest:tt)+) => {
        proc_macro_expr_decl_helper!(($($attrs)* #[$first]) $($rest)+);
    };
    (($($attrs:tt)*) $name:ident ! => $name_impl:ident) => {
        #[derive(ProcMacroHackExpr)]
        #[allow(unused, non_camel_case_types)]
        $($attrs)*
        enum $name {
            $name_impl
        }
    };
    (($($attrs:tt)*) $name:ident ! => $name_impl:ident #[$first:meta] $($rest:tt)+) => {
        proc_macro_expr_decl_helper!(($($attrs)*) $name ! => $name_impl);
        proc_macro_expr_decl_helper!((#[$first]) $($rest)+);
    };
}

#[macro_export]
macro_rules! proc_macro_item_decl {
    (#[$attr:meta] $($rest:tt)+) => {
        proc_macro_item_decl_helper!((#[$attr]) $($rest)+);
    };
    ($name:ident ! => $name_impl:ident) => {
        proc_macro_item_decl_helper!(() $name ! => $name_impl);
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! proc_macro_item_decl_helper {
    (($($attrs:tt)*) #[$first:meta] $($rest:tt)+) => {
        proc_macro_item_decl_helper!(($($attrs)* #[$first]) $($rest)+);
    };
    (($($attrs:tt)*) $name:ident ! => $name_impl:ident) => {
        #[derive(ProcMacroHackItem)]
        #[allow(unused, non_camel_case_types)]
        $($attrs)*
        enum $name {
            $name_impl
        }
    };
    (($($attrs:tt)*) $name:ident ! => $name_impl:ident #[$first:meta] $($rest:tt)+) => {
        proc_macro_item_decl_helper!(($($attrs)*) $name ! => $name_impl);
        proc_macro_item_decl_helper!((#[$first]) $($rest)+);
    };
}

#[macro_export]
macro_rules! proc_macro_expr_impl {
    ($(
        $( #[$attr:meta] )*
        pub fn $func:ident($input:ident: &str) -> String $body:block
    )+) => {
        $(
            // Parses an input that looks like:
            //
            // ```
            // #[allow(unused)]
            // enum ProcMacroHack {
            //     Input = (stringify!(ARGS), 0).1,
            // }
            // ```
            $( #[$attr] )*
            #[proc_macro_derive($func)]
            pub fn $func(input: proc_macro_tokenstream!()) -> proc_macro_tokenstream!() {
                let source = input.to_string();
                let source = source.trim();

                let prefix = "#[allow(unused)]\nenum ProcMacroHack {";
                let suffix = "}";
                assert!(source.starts_with(prefix));
                assert!(source.ends_with(suffix));
                let source = &source[prefix.len() .. source.len() - suffix.len()].trim();

                let prefix = "Input =";
                let suffix = "0).1,";
                assert!(source.starts_with(prefix));
                assert!(source.ends_with(suffix));
                let source = &source[prefix.len() .. source.len() - suffix.len()].trim();

                let prefix = "(stringify!(";
                let suffix = "),";
                assert!(source.starts_with(prefix));
                assert!(source.ends_with(suffix));
                let tokens = &source[prefix.len() .. source.len() - suffix.len()].trim();

                fn func($input: &str) -> String $body

                format!("
                    macro_rules! proc_macro_call {{
                        () => {{
                            {}
                        }}
                    }}
                ", func(tokens)).parse().unwrap()
            }
        )+
    }
}

#[macro_export]
macro_rules! proc_macro_item_impl {
    ($(
        $( #[$attr:meta] )*
        pub fn $func:ident($input:ident: &str) -> String $body:block
    )+) => {
        $(
            // Parses an input that looks like:
            //
            // ```
            // #[allow(unused)]
            // enum ProcMacroHack {
            //     Input = (stringify!(ARGS), 0).1,
            // }
            // ```
            $( #[$attr] )*
            #[proc_macro_derive($func)]
            pub fn $func(input: proc_macro_tokenstream!()) -> proc_macro_tokenstream!() {
                let source = input.to_string();
                let source = source.trim();

                let prefix = "#[allow(unused)]\nenum ProcMacroHack {";
                let suffix = "}";
                assert!(source.starts_with(prefix));
                assert!(source.ends_with(suffix));
                let source = &source[prefix.len() .. source.len() - suffix.len()].trim();

                let prefix = "Input =";
                let suffix = "0).1,";
                assert!(source.starts_with(prefix));
                assert!(source.ends_with(suffix));
                let source = &source[prefix.len() .. source.len() - suffix.len()].trim();

                let prefix = "(stringify!(";
                let suffix = "),";
                assert!(source.starts_with(prefix));
                assert!(source.ends_with(suffix));
                let tokens = &source[prefix.len() .. source.len() - suffix.len()].trim();

                fn func($input: &str) -> String $body

                func(tokens).parse().unwrap()
            }
        )+
    }
}
<commit_msg>Document the public macros<commit_after>//! ## Defining procedural macros
//!
//! Two crates are required to define a macro.
//!
//! ### The declaration crate
//!
//! This crate is allowed to contain other public things if you need, for example
//! traits or functions or ordinary macros.
//!
//! https://github.com/dtolnay/proc-macro-hack/tree/master/demo-hack
//!
//! ```rust,ignore
//! #[macro_use]
//! extern crate proc_macro_hack;
//!
//! #[allow(unused_imports)]
//! #[macro_use]
//! extern crate demo_hack_impl;
//! #[doc(hidden)]
//! pub use demo_hack_impl::*;
//!
//! proc_macro_expr_decl! {
//!     /// Add one to an expression.
//!     add_one! => add_one_impl
//! }
//!
//! proc_macro_item_decl! {
//!     /// A function that always returns 2.
//!     two_fn! => two_fn_impl
//! }
//! ```
//!
//! ### The implementation crate
//!
//! This crate must contain nothing but procedural macros. Private helper functions
//! and private modules are fine but nothing can be public.
//!
//! https://github.com/dtolnay/proc-macro-hack/tree/master/demo-hack-impl
//!
//! ```rust,ignore
//! #[macro_use]
//! extern crate proc_macro_hack;
//!
//! proc_macro_expr_impl! {
//!     /// Add one to an expression.
//!     pub fn add_one_impl(input: &str) -> String {
//!         format!("1 + {}", input)
//!     }
//! }
//!
//! proc_macro_item_impl! {
//!     /// A function that always returns 2.
//!     pub fn two_fn_impl(input: &str) -> String {
//!         format!("fn {}() -> u8 {{ 2 }}", input)
//!     }
//! }
//! ```
//!
//! Both crates depend on `proc-macro-hack`:
//!
//! ```toml
//! [dependencies]
//! proc-macro-hack = "0.3"
//! ```
//!
//! Additionally, your implementation crate (but not your declaration crate) is a
//! proc macro:
//!
//! ```toml
//! [lib]
//! proc-macro = true
//! ```
//!
//! ## Using procedural macros
//!
//! Users of your crate depend on your declaration crate (not your implementation
//! crate), then use your procedural macros as though it were magic. They even get
//! reasonable error messages if your procedural macro panics.
//!
//! https://github.com/dtolnay/proc-macro-hack/tree/master/example
//!
//! ```rust,ignore
//! #[macro_use]
//! extern crate demo_hack;
//!
//! two_fn!(two);
//!
//! fn main() {
//!     let x = two();
//!     let nine = add_one!(x) + add_one!(2 + 3);
//!     println!("nine = {}", nine);
//! }
//! ```
//!
//! ---
//!
//! # Expansion of expression macros
//!
//! ```rust,ignore
//! m!(ARGS)
//! ```
//!
//! ... expands to ...
//!
//! ```rust,ignore
//! {
//!     #[derive(m_impl)]
//!     #[allow(unused)]
//!     enum ProcMacroHack {
//!         Input = (stringify!(ARGS), 0).1,
//!     }
//!     proc_macro_call!()
//! }
//! ```
//!
//! ... expands to ...
//!
//! ```rust,ignore
//! {
//!     macro_rules! proc_macro_call {
//!         () => { RESULT }
//!     }
//!     proc_macro_call!()
//! }
//! ```
//!
//! ... expands to ...
//!
//! ```rust,ignore
//! {
//!     RESULT
//! }
//! ```
//!
//! # Expansion of item macros
//!
//! ```rust,ignore
//! m!(ARGS);
//! ```
//!
//! ... expands to ...
//!
//! ```rust,ignore
//! #[derive(m_impl)]
//! #[allow(unused)]
//! enum ProcMacroHack {
//!     Input = (stringify!(ARGS), 0).1,
//! }
//! ```
//!
//! ... expands to ...
//!
//! ```rust,ignore
//! RESULT
//! ```

#[cfg(feature = "proc_macro")]
extern crate proc_macro;

// Allow the "unused" #[macro_use] because there is a different un-ignorable
// warning otherwise:
//
//    proc macro crates and `#[no_link]` crates have no effect without `#[macro_use]`
#[allow(unused_imports)]
#[macro_use]
extern crate proc_macro_hack_impl;
#[doc(hidden)]
pub use proc_macro_hack_impl::*;

#[cfg(feature = "proc_macro")]
#[doc(hidden)]
pub use proc_macro::TokenStream;

#[cfg(feature = "proc_macro")]
#[doc(hidden)]
#[macro_export]
macro_rules! proc_macro_tokenstream {
    () => {
        $crate::TokenStream
    }
}

#[cfg(not(feature = "proc_macro"))]
#[doc(hidden)]
#[macro_export]
macro_rules! proc_macro_tokenstream {
    () => {
        ::proc_macro::TokenStream
    }
}

/// Declare a hacky procedural macro that expands to an expression.
///
/// ```rust,ignore
/// proc_macro_expr_decl! {
///     /// Add one to an expression.
///     add_one! => add_one_impl
/// }
/// ```
#[macro_export]
macro_rules! proc_macro_expr_decl {
    (#[$attr:meta] $($rest:tt)+) => {
        proc_macro_expr_decl_helper!((#[$attr]) $($rest)+);
    };
    ($name:ident ! => $name_impl:ident) => {
        proc_macro_expr_decl_helper!(() $name ! => $name_impl);
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! proc_macro_expr_decl_helper {
    (($($attrs:tt)*) #[$first:meta] $($rest:tt)+) => {
        proc_macro_expr_decl_helper!(($($attrs)* #[$first]) $($rest)+);
    };
    (($($attrs:tt)*) $name:ident ! => $name_impl:ident) => {
        #[derive(ProcMacroHackExpr)]
        #[allow(unused, non_camel_case_types)]
        $($attrs)*
        enum $name {
            $name_impl
        }
    };
    (($($attrs:tt)*) $name:ident ! => $name_impl:ident #[$first:meta] $($rest:tt)+) => {
        proc_macro_expr_decl_helper!(($($attrs)*) $name ! => $name_impl);
        proc_macro_expr_decl_helper!((#[$first]) $($rest)+);
    };
}

/// Declare a hacky procedural macro that expands to items.
///
/// ```rust,ignore
/// proc_macro_item_decl! {
///     /// A function that always returns 2.
///     two_fn! => two_fn_impl
/// }
/// ```
#[macro_export]
macro_rules! proc_macro_item_decl {
    (#[$attr:meta] $($rest:tt)+) => {
        proc_macro_item_decl_helper!((#[$attr]) $($rest)+);
    };
    ($name:ident ! => $name_impl:ident) => {
        proc_macro_item_decl_helper!(() $name ! => $name_impl);
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! proc_macro_item_decl_helper {
    (($($attrs:tt)*) #[$first:meta] $($rest:tt)+) => {
        proc_macro_item_decl_helper!(($($attrs)* #[$first]) $($rest)+);
    };
    (($($attrs:tt)*) $name:ident ! => $name_impl:ident) => {
        #[derive(ProcMacroHackItem)]
        #[allow(unused, non_camel_case_types)]
        $($attrs)*
        enum $name {
            $name_impl
        }
    };
    (($($attrs:tt)*) $name:ident ! => $name_impl:ident #[$first:meta] $($rest:tt)+) => {
        proc_macro_item_decl_helper!(($($attrs)*) $name ! => $name_impl);
        proc_macro_item_decl_helper!((#[$first]) $($rest)+);
    };
}

/// Implement a hacky procedural macro that expands to an expression.
///
/// ```rust,ignore
/// proc_macro_expr_impl! {
///     /// Add one to an expression.
///     pub fn add_one_impl(input: &str) -> String {
///         format!("1 + {}", input)
///     }
/// }
/// ```
#[macro_export]
macro_rules! proc_macro_expr_impl {
    ($(
        $( #[$attr:meta] )*
        pub fn $func:ident($input:ident: &str) -> String $body:block
    )+) => {
        $(
            // Parses an input that looks like:
            //
            // ```
            // #[allow(unused)]
            // enum ProcMacroHack {
            //     Input = (stringify!(ARGS), 0).1,
            // }
            // ```
            $( #[$attr] )*
            #[proc_macro_derive($func)]
            pub fn $func(input: proc_macro_tokenstream!()) -> proc_macro_tokenstream!() {
                let source = input.to_string();
                let source = source.trim();

                let prefix = "#[allow(unused)]\nenum ProcMacroHack {";
                let suffix = "}";
                assert!(source.starts_with(prefix));
                assert!(source.ends_with(suffix));
                let source = &source[prefix.len() .. source.len() - suffix.len()].trim();

                let prefix = "Input =";
                let suffix = "0).1,";
                assert!(source.starts_with(prefix));
                assert!(source.ends_with(suffix));
                let source = &source[prefix.len() .. source.len() - suffix.len()].trim();

                let prefix = "(stringify!(";
                let suffix = "),";
                assert!(source.starts_with(prefix));
                assert!(source.ends_with(suffix));
                let tokens = &source[prefix.len() .. source.len() - suffix.len()].trim();

                fn func($input: &str) -> String $body

                format!("
                    macro_rules! proc_macro_call {{
                        () => {{
                            {}
                        }}
                    }}
                ", func(tokens)).parse().unwrap()
            }
        )+
    }
}

/// Implement a hacky procedural macro that expands to items.
///
/// ```rust,ignore
/// proc_macro_item_impl! {
///     /// A function that always returns 2.
///     pub fn two_fn_impl(input: &str) -> String {
///         format!("fn {}() -> u8 {{ 2 }}", input)
///     }
/// }
/// ```
#[macro_export]
macro_rules! proc_macro_item_impl {
    ($(
        $( #[$attr:meta] )*
        pub fn $func:ident($input:ident: &str) -> String $body:block
    )+) => {
        $(
            // Parses an input that looks like:
            //
            // ```
            // #[allow(unused)]
            // enum ProcMacroHack {
            //     Input = (stringify!(ARGS), 0).1,
            // }
            // ```
            $( #[$attr] )*
            #[proc_macro_derive($func)]
            pub fn $func(input: proc_macro_tokenstream!()) -> proc_macro_tokenstream!() {
                let source = input.to_string();
                let source = source.trim();

                let prefix = "#[allow(unused)]\nenum ProcMacroHack {";
                let suffix = "}";
                assert!(source.starts_with(prefix));
                assert!(source.ends_with(suffix));
                let source = &source[prefix.len() .. source.len() - suffix.len()].trim();

                let prefix = "Input =";
                let suffix = "0).1,";
                assert!(source.starts_with(prefix));
                assert!(source.ends_with(suffix));
                let source = &source[prefix.len() .. source.len() - suffix.len()].trim();

                let prefix = "(stringify!(";
                let suffix = "),";
                assert!(source.starts_with(prefix));
                assert!(source.ends_with(suffix));
                let tokens = &source[prefix.len() .. source.len() - suffix.len()].trim();

                fn func($input: &str) -> String $body

                func(tokens).parse().unwrap()
            }
        )+
    }
}
<|endoftext|>


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

#![crate_name = "xlib"]
#![crate_type = "lib"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]

#![feature(globs)]

extern crate libc;

pub use xlib::*;
mod xlib;
<commit_msg>Fixed a warning about globs: this feature was added to Rust.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name = "xlib"]
#![crate_type = "lib"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]

extern crate libc;

pub use xlib::*;
mod xlib;
<|endoftext|>


<commit_before>mod client;
mod message;

pub use client::Client;
pub use message::{Message, OwnedMessage, ParseError};
<commit_msg>Export ReadError<commit_after>mod client;
mod message;

pub use client::{Client, ReadError};
pub use message::{Message, OwnedMessage, ParseError};
<|endoftext|>


<commit_before>//! This crate is a reimplementation
//! of GNU gettext translation framework in Rust.
//! It allows your Rust programs to parse out GNU MO files
//! containing translations and use them in your user interface.
//!
//! It contains several differences from the official C implementation.
//! Notably, this crate does not in any way depend on a global locale
//! ([2.2](https://www.gnu.org/software/gettext/manual/gettext.html#Setting-the-GUI-Locale))
//! and does not enforce a directory structure
//! for storing your translation catalogs
//! ([11.2.3](https://www.gnu.org/software/gettext/manual/gettext.html#Locating-Catalogs)).
//! Instead, the choice of translation catalog to use is explicitly made by the user.
//!
//! This crate is still in-progress
//! and may not be on par with the original implementation feature-wise.
//!
//! For the exact feature parity see the roadmap in the
//! [README](https://github.com/justinas/gettext#readme).
//!
//! # Example
//!
//! ```ignore
//! extern crate gettext;
//!
//! use std::fs::File;
//! use gettext::Catalog;
//!
//! fn main() {
//!     let f = File::open("french.mo").expect("could not open the catalog");
//!     let catalog = Catalog::parse(f).expect("could not parse the catalog");
//!
//!     // Will print out the French translation
//!     // if it is found in the parsed file
//!     // or "Name" otherwise.
//!     println!("{}", catalog.gettext("Name"));
//! }
//! ```

// https://pascalhertleif.de/artikel/good-practices-for-writing-rust-libraries/
#![deny(missing_docs, missing_debug_implementations,
        trivial_casts, trivial_numeric_casts, unused_import_braces)]

mod parser;

use std::collections::HashMap;
use std::io::Read;
use std::ops::Deref;

use parser::parse_catalog;

pub use parser::Error;

/// Returns the number of the appropriate plural form
/// for the given count `n` of objects for germanic languages.
fn plural_form(n: usize) -> usize {
    if n != 1 {
        1
    } else {
        0
    }
}

fn key_with_context(context: &str, key: &str) -> String {
    let mut result = context.to_owned();
    result.push('\x04');
    result.push_str(key);
    result
}

/// Catalog represents a set of translation strings
/// parsed out of one MO file.
#[derive(Debug)]
pub struct Catalog {
    strings: HashMap<String, Message>,
}

impl Catalog {
    /// Creates a new, empty gettext catalog.
    fn new() -> Self {
        Catalog { strings: HashMap::new() }
    }

    /// Parses a gettext catalog from the given binary MO file.
    /// Returns the `Err` variant upon encountering an invalid file format
    /// or invalid byte sequence in strings.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use gettext::Catalog;
    /// use std::fs::File;
    ///
    /// let file = File::open("french.mo").unwrap();
    /// let catalog = Catalog::parse(file).unwrap();
    /// ```

    pub fn parse<R: Read>(reader: R) -> Result<Self, parser::Error> {
        parse_catalog(reader)
    }

    fn insert(&mut self, msg: Message) {
        let key = match msg.context {
            Some(ref ctxt) => key_with_context(ctxt, &msg.id),
            None => msg.id.clone(),
        };
        self.strings.insert(key, msg);
    }

    /// Returns the singular translation of `msg_id` from the given catalog
    /// or `msg_id` itself if a translation does not exist.
    pub fn gettext<'a>(&'a self, msg_id: &'a str) -> &'a str {
        self.strings.get(&msg_id.to_owned()).and_then(|msg| msg.get_translated(0)).unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id` from the given catalog
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    ///
    /// Currently, the only supported plural formula is `n != 1`.
    pub fn ngettext<'a>(&'a self, msg_id: &'a str, msg_id_plural: &'a str, n: usize) -> &'a str {
        let form_no = plural_form(n);

        match self.strings.get(&msg_id.to_owned()) {
            Some(msg) => {
                msg.get_translated(form_no).unwrap_or_else(|| [msg_id, msg_id_plural][form_no])
            }
            None if form_no == 0 => msg_id,
            None if form_no == 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }

    /// Returns the singular translation of `msg_id`
    /// in the context `msg_context`
    /// or `msg_id` itself if a translation does not exist.
    // TODO: DRY gettext/pgettext
    pub fn pgettext<'a>(&'a self, msg_context: &'a str, msg_id: &'a str) -> &'a str {
        let key = key_with_context(msg_context, &msg_id);
        self.strings.get(&key).and_then(|msg| msg.get_translated(0)).unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id`
    /// in the context `msg_context`
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    ///
    /// Currently, the only supported plural formula is `n != 1`.
    // TODO: DRY ngettext/npgettext
    pub fn npgettext<'a>(&'a self,
                         msg_context: &'a str,
                         msg_id: &'a str,
                         msg_id_plural: &'a str,
                         n: usize)
                         -> &'a str {
        let key = key_with_context(msg_context, &msg_id);
        let form_no = plural_form(n);
        match self.strings.get(&key) {
            Some(msg) => {
                msg.get_translated(form_no).unwrap_or_else(|| [msg_id, msg_id_plural][form_no])
            }
            None if form_no == 0 => msg_id,
            None if form_no == 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }
}

#[derive(Debug, Eq, PartialEq)]
struct Message {
    id: String,
    context: Option<String>,
    translated: Vec<String>,
}

impl Message {
    fn new<T: Into<String>>(id: T, context: Option<T>, translated: Vec<T>) -> Self {
        Message {
            id: id.into(),
            context: context.map(Into::into),
            translated: translated.into_iter().map(Into::into).collect(),
        }
    }

    fn get_translated(&self, form_no: usize) -> Option<&str> {
        self.translated.get(form_no).map(|s| s.deref())
    }
}

#[test]
fn catalog_insert() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("thisisid", None, vec![]));
    cat.insert(Message::new("anotherid", Some("context"), vec![]));
    let mut keys = cat.strings.keys().collect::<Vec<_>>();
    keys.sort();
    assert_eq!(keys, &["context\x04anotherid", "thisisid"])
}

#[test]
fn catalog_gettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", None, vec!["Tekstas"]));
    cat.insert(Message::new("Image", Some("context"), vec!["Paveikslelis"]));
    assert_eq!(cat.gettext("Text"), "Tekstas");
    assert_eq!(cat.gettext("Image"), "Image");
}

#[test]
fn catalog_ngettext() {
    let mut cat = Catalog::new();
    {
        // n == 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Text");
        // n != 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Texts");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Texts");
    }
    {
        cat.insert(Message::new("Text", None, vec!["Tekstas", "Tekstai"]));
        // n == 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Tekstas");
        // n != 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Tekstai");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Tekstai");
    }
}

#[test]
fn catalog_pgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", Some("unit test"), vec!["Tekstas"]));
    assert_eq!(cat.pgettext("unit test", "Text"), "Tekstas");
    assert_eq!(cat.pgettext("integration test", "Text"), "Text");
}

#[test]
fn catalog_npgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", Some("unit test"), vec!["Tekstas", "Tekstai"]));

    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 1), "Tekstas");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 0), "Tekstai");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 2), "Tekstai");

    assert_eq!(cat.npgettext("integration test", "Text", "Texts", 1),
               "Text");
    assert_eq!(cat.npgettext("integration test", "Text", "Texts", 0),
               "Texts");
    assert_eq!(cat.npgettext("integration test", "Text", "Texts", 2),
               "Texts");
}
<commit_msg>Remove an unnecesarry allocation<commit_after>//! This crate is a reimplementation
//! of GNU gettext translation framework in Rust.
//! It allows your Rust programs to parse out GNU MO files
//! containing translations and use them in your user interface.
//!
//! It contains several differences from the official C implementation.
//! Notably, this crate does not in any way depend on a global locale
//! ([2.2](https://www.gnu.org/software/gettext/manual/gettext.html#Setting-the-GUI-Locale))
//! and does not enforce a directory structure
//! for storing your translation catalogs
//! ([11.2.3](https://www.gnu.org/software/gettext/manual/gettext.html#Locating-Catalogs)).
//! Instead, the choice of translation catalog to use is explicitly made by the user.
//!
//! This crate is still in-progress
//! and may not be on par with the original implementation feature-wise.
//!
//! For the exact feature parity see the roadmap in the
//! [README](https://github.com/justinas/gettext#readme).
//!
//! # Example
//!
//! ```ignore
//! extern crate gettext;
//!
//! use std::fs::File;
//! use gettext::Catalog;
//!
//! fn main() {
//!     let f = File::open("french.mo").expect("could not open the catalog");
//!     let catalog = Catalog::parse(f).expect("could not parse the catalog");
//!
//!     // Will print out the French translation
//!     // if it is found in the parsed file
//!     // or "Name" otherwise.
//!     println!("{}", catalog.gettext("Name"));
//! }
//! ```

// https://pascalhertleif.de/artikel/good-practices-for-writing-rust-libraries/
#![deny(missing_docs, missing_debug_implementations,
        trivial_casts, trivial_numeric_casts, unused_import_braces)]

mod parser;

use std::collections::HashMap;
use std::io::Read;
use std::ops::Deref;

use parser::parse_catalog;

pub use parser::Error;

/// Returns the number of the appropriate plural form
/// for the given count `n` of objects for germanic languages.
fn plural_form(n: usize) -> usize {
    if n != 1 {
        1
    } else {
        0
    }
}

fn key_with_context(context: &str, key: &str) -> String {
    let mut result = context.to_owned();
    result.push('\x04');
    result.push_str(key);
    result
}

/// Catalog represents a set of translation strings
/// parsed out of one MO file.
#[derive(Debug)]
pub struct Catalog {
    strings: HashMap<String, Message>,
}

impl Catalog {
    /// Creates a new, empty gettext catalog.
    fn new() -> Self {
        Catalog { strings: HashMap::new() }
    }

    /// Parses a gettext catalog from the given binary MO file.
    /// Returns the `Err` variant upon encountering an invalid file format
    /// or invalid byte sequence in strings.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use gettext::Catalog;
    /// use std::fs::File;
    ///
    /// let file = File::open("french.mo").unwrap();
    /// let catalog = Catalog::parse(file).unwrap();
    /// ```

    pub fn parse<R: Read>(reader: R) -> Result<Self, parser::Error> {
        parse_catalog(reader)
    }

    fn insert(&mut self, msg: Message) {
        let key = match msg.context {
            Some(ref ctxt) => key_with_context(ctxt, &msg.id),
            None => msg.id.clone(),
        };
        self.strings.insert(key, msg);
    }

    /// Returns the singular translation of `msg_id` from the given catalog
    /// or `msg_id` itself if a translation does not exist.
    pub fn gettext<'a>(&'a self, msg_id: &'a str) -> &'a str {
        self.strings.get(msg_id).and_then(|msg| msg.get_translated(0)).unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id` from the given catalog
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    ///
    /// Currently, the only supported plural formula is `n != 1`.
    pub fn ngettext<'a>(&'a self, msg_id: &'a str, msg_id_plural: &'a str, n: usize) -> &'a str {
        let form_no = plural_form(n);

        match self.strings.get(msg_id) {
            Some(msg) => {
                msg.get_translated(form_no).unwrap_or_else(|| [msg_id, msg_id_plural][form_no])
            }
            None if form_no == 0 => msg_id,
            None if form_no == 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }

    /// Returns the singular translation of `msg_id`
    /// in the context `msg_context`
    /// or `msg_id` itself if a translation does not exist.
    // TODO: DRY gettext/pgettext
    pub fn pgettext<'a>(&'a self, msg_context: &'a str, msg_id: &'a str) -> &'a str {
        let key = key_with_context(msg_context, &msg_id);
        self.strings.get(&key).and_then(|msg| msg.get_translated(0)).unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id`
    /// in the context `msg_context`
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    ///
    /// Currently, the only supported plural formula is `n != 1`.
    // TODO: DRY ngettext/npgettext
    pub fn npgettext<'a>(&'a self,
                         msg_context: &'a str,
                         msg_id: &'a str,
                         msg_id_plural: &'a str,
                         n: usize)
                         -> &'a str {
        let key = key_with_context(msg_context, &msg_id);
        let form_no = plural_form(n);
        match self.strings.get(&key) {
            Some(msg) => {
                msg.get_translated(form_no).unwrap_or_else(|| [msg_id, msg_id_plural][form_no])
            }
            None if form_no == 0 => msg_id,
            None if form_no == 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }
}

#[derive(Debug, Eq, PartialEq)]
struct Message {
    id: String,
    context: Option<String>,
    translated: Vec<String>,
}

impl Message {
    fn new<T: Into<String>>(id: T, context: Option<T>, translated: Vec<T>) -> Self {
        Message {
            id: id.into(),
            context: context.map(Into::into),
            translated: translated.into_iter().map(Into::into).collect(),
        }
    }

    fn get_translated(&self, form_no: usize) -> Option<&str> {
        self.translated.get(form_no).map(|s| s.deref())
    }
}

#[test]
fn catalog_insert() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("thisisid", None, vec![]));
    cat.insert(Message::new("anotherid", Some("context"), vec![]));
    let mut keys = cat.strings.keys().collect::<Vec<_>>();
    keys.sort();
    assert_eq!(keys, &["context\x04anotherid", "thisisid"])
}

#[test]
fn catalog_gettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", None, vec!["Tekstas"]));
    cat.insert(Message::new("Image", Some("context"), vec!["Paveikslelis"]));
    assert_eq!(cat.gettext("Text"), "Tekstas");
    assert_eq!(cat.gettext("Image"), "Image");
}

#[test]
fn catalog_ngettext() {
    let mut cat = Catalog::new();
    {
        // n == 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Text");
        // n != 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Texts");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Texts");
    }
    {
        cat.insert(Message::new("Text", None, vec!["Tekstas", "Tekstai"]));
        // n == 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Tekstas");
        // n != 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Tekstai");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Tekstai");
    }
}

#[test]
fn catalog_pgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", Some("unit test"), vec!["Tekstas"]));
    assert_eq!(cat.pgettext("unit test", "Text"), "Tekstas");
    assert_eq!(cat.pgettext("integration test", "Text"), "Text");
}

#[test]
fn catalog_npgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", Some("unit test"), vec!["Tekstas", "Tekstai"]));

    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 1), "Tekstas");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 0), "Tekstai");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 2), "Tekstai");

    assert_eq!(cat.npgettext("integration test", "Text", "Texts", 1),
               "Text");
    assert_eq!(cat.npgettext("integration test", "Text", "Texts", 0),
               "Texts");
    assert_eq!(cat.npgettext("integration test", "Text", "Texts", 2),
               "Texts");
}
<|endoftext|>


<commit_before>//! Clutter is a GObject based library for creating fast, visually rich,
//! graphical user interfaces.
//!
//! ---------------------------------------------------------------------------
//!
//! This library is free software; you can redistribute it and/or modify it
//! under the terms of the GNU Library General Public License as published by
//! the Free Software Foundation; either version 2 of the License, or (at your
//! option) any later version.
//!
//! This library is distributed in the hope that it will be useful, but WITHOUT
//! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
//! FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
//! License for more details.
//!
//! You may obtain a copy of the GNU Library General Public License from the
//! Free Software Foundation by visiting their Web site or by writing to:
//!
//! Free Software Foundation, Inc.
//! 59 Temple Place - Suite 330
//! Boston, MA 02111-1307
//! USA
//!
//! ---------------------------------------------------------------------------
//!
//! Permission is granted to copy, distribute and/or modify this documentation
//! under the terms of the GNU Free Documentation License, Version 1.1 or any
//! later version published by the Free Software Foundation with no Invariant
//! Sections, no Front-Cover Texts, and no Back-Cover Texts. You may obtain a
//! copy of the GNU Free Documentation License from the Free Software
//! Foundation by visiting their Web site or by writing to the address above.

extern crate cairo;
extern crate libc;

#[link(name = "gobject-2.0")] extern {}
#[link(name = "clutter-1.0")] extern {}

pub mod actor;
pub mod canvas;
pub mod color;
pub mod constraint;
pub mod content;
pub mod scaling;
pub mod stage;
pub mod text;

/// Initialises everything needed to operate with Clutter.
///
/// It is safe to call this function multiple times.
///
/// This function will not abort in case of errors during initialization;
/// `init()` will print out the error message on stderr, and will return an
/// error code. It is up to the application code to handle this case.
pub fn init() {
  unsafe {
    clutter_init(std::ptr::null_mut(), std::ptr::null_mut());
  }
}

/// Starts the Clutter mainloop.
pub fn main() {
  unsafe {
    clutter_main();
  }
}

/// Terminates the Clutter mainloop.
pub fn main_quit() {
  unsafe {
    clutter_main_quit();
  }
}

extern {
  fn clutter_init(argc: *mut i32, argv: *mut i32);
  fn clutter_main();
  fn clutter_main_quit();
}
<commit_msg>Add top-level stable declaration<commit_after>//! Clutter is a GObject based library for creating fast, visually rich,
//! graphical user interfaces.
//!
//! ---------------------------------------------------------------------------
//!
//! This library is free software; you can redistribute it and/or modify it
//! under the terms of the GNU Library General Public License as published by
//! the Free Software Foundation; either version 2 of the License, or (at your
//! option) any later version.
//!
//! This library is distributed in the hope that it will be useful, but WITHOUT
//! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
//! FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
//! License for more details.
//!
//! You may obtain a copy of the GNU Library General Public License from the
//! Free Software Foundation by visiting their Web site or by writing to:
//!
//! Free Software Foundation, Inc.
//! 59 Temple Place - Suite 330
//! Boston, MA 02111-1307
//! USA
//!
//! ---------------------------------------------------------------------------
//!
//! Permission is granted to copy, distribute and/or modify this documentation
//! under the terms of the GNU Free Documentation License, Version 1.1 or any
//! later version published by the Free Software Foundation with no Invariant
//! Sections, no Front-Cover Texts, and no Back-Cover Texts. You may obtain a
//! copy of the GNU Free Documentation License from the Free Software
//! Foundation by visiting their Web site or by writing to the address above.
#![stable]

extern crate cairo;
extern crate libc;

#[link(name = "gobject-2.0")] extern {}
#[link(name = "clutter-1.0")] extern {}

pub mod actor;
pub mod canvas;
pub mod color;
pub mod constraint;
pub mod content;
pub mod scaling;
pub mod stage;
pub mod text;

/// Initialises everything needed to operate with Clutter.
///
/// It is safe to call this function multiple times.
///
/// This function will not abort in case of errors during initialization;
/// `init()` will print out the error message on stderr, and will return an
/// error code. It is up to the application code to handle this case.
pub fn init() {
  unsafe {
    clutter_init(std::ptr::null_mut(), std::ptr::null_mut());
  }
}

/// Starts the Clutter mainloop.
pub fn main() {
  unsafe {
    clutter_main();
  }
}

/// Terminates the Clutter mainloop.
pub fn main_quit() {
  unsafe {
    clutter_main_quit();
  }
}

extern {
  fn clutter_init(argc: *mut i32, argv: *mut i32);
  fn clutter_main();
  fn clutter_main_quit();
}
<|endoftext|>


<commit_before>#[macro_use] extern crate bitflags;
extern crate gl as gl_lib;

#[macro_use] mod context;
mod buffer;
mod shader;
mod program;
mod vertex_data;
mod vertex_buffer;
mod index_data;
mod uniform_data;
mod types;

pub use gl_lib as gl;

pub use context::Context;
pub use buffer::{Buffer, BufferBinding, BufferDataUsage,
                 STREAM_DRAW, STATIC_DRAW, DYNAMIC_DRAW,
                 ArrayBufferBinder, ElementArrayBufferBinder,
                 ArrayBufferBinding, ElementArrayBufferBinding};
pub use shader::{Shader, ShaderType, VERTEX_SHADER, FRAGMENT_SHADER};
pub use program::{Program, ProgramAttrib, ProgramBinder, ProgramBinding};
pub use uniform_data::{UniformData, UniformDatum, UniformPrimitive,
                       UniformPrimitiveType, UniformDatumType};
pub use vertex_data::{VertexData, VertexDatum,
                      VertexBytes, VertexAttribBinder};
pub use index_data::{IndexData, IndexDatum, IndexDatumType};
pub use vertex_buffer::{VertexBuffer, VertexBufferBinding,
                        IndexBuffer, IndexBufferBinding};
pub use types::{Color, Viewport, GLError, BufferBits,
                DrawingMode, DataType,
                COLOR_BUFFER_BIT, DEPTH_BUFFER_BIT, STENCIL_BUFFER_BIT,
                POINTS, LINE_STRIP, LINE_LOOP, LINES,
                TRIANGLE_STRIP, TRIANGLE_FAN, TRIANGLES,
                BYTE, UNSIGNED_BYTE, SHORT, UNSIGNED_SHORT,
                FIXED, FLOAT};
<commit_msg>Export `ProgramUniform` externally<commit_after>#[macro_use] extern crate bitflags;
extern crate gl as gl_lib;

#[macro_use] mod context;
mod buffer;
mod shader;
mod program;
mod vertex_data;
mod vertex_buffer;
mod index_data;
mod uniform_data;
mod types;

pub use gl_lib as gl;

pub use context::Context;
pub use buffer::{Buffer, BufferBinding, BufferDataUsage,
                 STREAM_DRAW, STATIC_DRAW, DYNAMIC_DRAW,
                 ArrayBufferBinder, ElementArrayBufferBinder,
                 ArrayBufferBinding, ElementArrayBufferBinding};
pub use shader::{Shader, ShaderType, VERTEX_SHADER, FRAGMENT_SHADER};
pub use program::{Program, ProgramBinder, ProgramBinding,
                  ProgramAttrib, ProgramUniform};
pub use uniform_data::{UniformData, UniformDatum, UniformPrimitive,
                       UniformPrimitiveType, UniformDatumType};
pub use vertex_data::{VertexData, VertexDatum,
                      VertexBytes, VertexAttribBinder};
pub use index_data::{IndexData, IndexDatum, IndexDatumType};
pub use vertex_buffer::{VertexBuffer, VertexBufferBinding,
                        IndexBuffer, IndexBufferBinding};
pub use types::{Color, Viewport, GLError, BufferBits,
                DrawingMode, DataType,
                COLOR_BUFFER_BIT, DEPTH_BUFFER_BIT, STENCIL_BUFFER_BIT,
                POINTS, LINE_STRIP, LINE_LOOP, LINES,
                TRIANGLE_STRIP, TRIANGLE_FAN, TRIANGLES,
                BYTE, UNSIGNED_BYTE, SHORT, UNSIGNED_SHORT,
                FIXED, FLOAT};
<|endoftext|>


<commit_before>//! A simple library for parsing an XML file into an in-memory tree structure
//!
//! Not recommended for large XML files, as it will load the entire file into memory.
//!
//! # Example
//!
//! ```no_run
//! use xmltree::Element;
//! use std::fs::File;
//!
//! let data: &'static str = r##"
//! <?xml version="1.0" encoding="utf-8" standalone="yes"?>
//! <names>
//!     <name first="bob" last="jones" />
//!     <name first="elizabeth" last="smith" />
//! </names>
//! "##;
//!
//! let mut names_element = Element::parse(data.as_bytes()).unwrap();
//!
//! println!("{:#?}", names_element);
//! {
//!     // get first `name` element
//!     let name = names_element.get_mut_child("name").expect("Can't find name element");
//!     name.attributes.insert("suffix".to_owned(), "mr".to_owned());
//! }
//! names_element.write(File::create("result.xml").unwrap());
//!
//!
//! ```
extern crate xml;

use std::collections::HashMap;
use std::io::{Read, Write};
use std::borrow::Cow;
use std::fmt;

use xml::reader::{EventReader, XmlEvent};
pub use xml::namespace::Namespace;

/// Represents an XML element.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Element {
    /// This elements prefix, if any
    pub prefix: Option<String>,

    /// This elements namespace, if any
    pub namespace: Option<String>,

    /// The full list of namespaces, if any
    ///
    /// The `Namespace` type is exported from the `xml-rs` crate.
    pub namespaces: Option<Namespace>,

    /// The name of the Element.  Does not include any namespace info
    pub name: String,

    /// The Element attributes
    pub attributes: HashMap<String, String>,

    /// Children
    pub children: Vec<Element>,

    /// The text data for this element
    pub text: Option<String>,
}

/// Errors that can occur parsing XML
#[derive(Debug)]
pub enum ParseError {
    /// The XML is invalid
    MalformedXml(xml::reader::Error),
    /// This library is unable to process this XML. This can occur if, for
    /// example, the XML contains processing instructions.
    CannotParse,
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseError::MalformedXml(ref e) => write!(f, "Malformed XML. {}", e),
            ParseError::CannotParse => write!(f, "Cannot parse"),
        }
    }
}

impl std::error::Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::MalformedXml(..) => "Malformed XML",
            ParseError::CannotParse => "Cannot parse",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            ParseError::MalformedXml(ref e) => Some(e),
            ParseError::CannotParse => None,
        }
    }
}

fn build<B: Read>(reader: &mut EventReader<B>, mut elem: Element) -> Result<Element, ParseError> {
    loop {
        match reader.next() {
            Ok(XmlEvent::EndElement { ref name }) => {
                if name.local_name == elem.name {
                    return Ok(elem);
                } else {
                    return Err(ParseError::CannotParse);
                }
            }
            Ok(XmlEvent::StartElement { name, attributes, namespace }) => {
                let mut attr_map = HashMap::new();
                for attr in attributes {
                    attr_map.insert(attr.name.local_name, attr.value);
                }

                let new_elem = Element {
                    prefix: name.prefix,
                    namespace: name.namespace,
                    namespaces: if namespace.is_essentially_empty() {
                        None
                    } else {
                        Some(namespace)
                    },
                    name: name.local_name,
                    attributes: attr_map,
                    children: Vec::new(),
                    text: None,
                };
                elem.children.push(try!(build(reader, new_elem)));
            }
            Ok(XmlEvent::Characters(s)) => {
                elem.text = Some(s);
            }
            Ok(XmlEvent::Whitespace(..)) | Ok(XmlEvent::Comment(..))=> (),
            Ok(XmlEvent::CData(s)) => elem.text = Some(s),
            Ok(XmlEvent::StartDocument { .. }) |
            Ok(XmlEvent::EndDocument) |
            Ok(XmlEvent::ProcessingInstruction { .. }) => return Err(ParseError::CannotParse),
            Err(e) => return Err(ParseError::MalformedXml(e)),
        }
    }

}

impl Element {
    /// Create a new empty element with given name
    ///
    /// All other fields are empty
    pub fn new(name: &str) -> Element {
        Element {
            name: String::from(name),
            prefix: None,
            namespace: None,
            namespaces: None,
            attributes: HashMap::new(),
            children: Vec::new(),
            text: None,
        }
    }

    /// Parses some data into an Element
    pub fn parse<R: Read>(r: R) -> Result<Element, ParseError> {
        let mut reader = EventReader::new(r);
        loop {
            match reader.next() {
                Ok(XmlEvent::StartElement { name, attributes, namespace }) => {
                    let mut attr_map = HashMap::new();
                    for attr in attributes {
                        attr_map.insert(attr.name.local_name, attr.value);
                    }

                    let root = Element {
                        prefix: name.prefix,
                        namespace: name.namespace,
                        namespaces: if namespace.is_essentially_empty() {
                            None
                        } else {
                            Some(namespace)
                        },
                        name: name.local_name,
                        attributes: attr_map,
                        children: Vec::new(),
                        text: None,
                    };
                    return build(&mut reader, root);
                }
                Ok(XmlEvent::Comment(..)) |
                Ok(XmlEvent::Whitespace(..)) |
                Ok(XmlEvent::StartDocument { .. }) => continue,
                Ok(XmlEvent::EndDocument) |
                Ok(XmlEvent::EndElement { .. }) |
                Ok(XmlEvent::Characters(..)) |
                Ok(XmlEvent::CData(..)) |
                Ok(XmlEvent::ProcessingInstruction { .. }) => return Err(ParseError::CannotParse),
                Err(e) => return Err(ParseError::MalformedXml(e)),
            }
        }
    }

    fn _write<B: Write>(&self, emitter: &mut xml::writer::EventWriter<B>) {
        use xml::writer::events::XmlEvent;
        use xml::name::Name;
        use xml::namespace::Namespace;
        use xml::attribute::Attribute;

        let mut name = Name::local(&self.name);
        if let Some(ref ns) = self.namespace {
            name.namespace = Some(ns);
        }
        if let Some(ref p) = self.prefix {
            name.prefix = Some(p);
        }

        let mut attributes = Vec::with_capacity(self.attributes.len());
        for (k, v) in &self.attributes {
            attributes.push(Attribute {
                                name: Name::local(k),
                                value: v,
                            });
        }

        let empty_ns = Namespace::empty();
        let namespace = if let Some(ref ns) = self.namespaces {
            Cow::Borrowed(ns)
        } else {
            Cow::Borrowed(&empty_ns)
        };

        emitter.write(XmlEvent::StartElement {
                          name: name,
                          attributes: Cow::Owned(attributes),
                          namespace: namespace,
                      })
            .unwrap();
        if let Some(ref t) = self.text {
            emitter.write(XmlEvent::Characters(t)).unwrap();
        }
        for elem in &self.children {
            elem._write(emitter);
        }
        emitter.write(XmlEvent::EndElement { name: Some(name) }).unwrap();
    }

    /// Writes out this element as the root element in an new XML document
    pub fn write<W: Write>(&self, w: W) {
        use xml::writer::EventWriter;
        use xml::writer::events::XmlEvent;
        use xml::common::XmlVersion;

        let mut emitter = EventWriter::new(w);
        emitter.write(XmlEvent::StartDocument {
                          version: XmlVersion::Version10,
                          encoding: None,
                          standalone: None,
                      })
            .unwrap();
        self._write(&mut emitter);
    }

    /// Find a child element with the given name and return a reference to it.
    pub fn get_child<K>(&self, k: K) -> Option<&Element>
        where String: PartialEq<K>
    {
        self.children.iter().find(|e| e.name == k)
    }

    /// Find a child element with the given name and return a mutable reference to it.
    pub fn get_mut_child<K>(&mut self, k: K) -> Option<&mut Element>
        where String: PartialEq<K>
    {
        self.children.iter_mut().find(|e| e.name == k)
    }

    /// Find a child element with the given name, remove and return it.
    pub fn take_child<K>(&mut self, k: K) -> Option<Element>
        where String: PartialEq<K>
    {
        self.children
            .iter()
            .position(|e| e.name == k)
            .map(|i| self.children.remove(i))
    }
}
<commit_msg>Add write_with_config()<commit_after>//! A simple library for parsing an XML file into an in-memory tree structure
//!
//! Not recommended for large XML files, as it will load the entire file into memory.
//!
//! # Example
//!
//! ```no_run
//! use xmltree::Element;
//! use std::fs::File;
//!
//! let data: &'static str = r##"
//! <?xml version="1.0" encoding="utf-8" standalone="yes"?>
//! <names>
//!     <name first="bob" last="jones" />
//!     <name first="elizabeth" last="smith" />
//! </names>
//! "##;
//!
//! let mut names_element = Element::parse(data.as_bytes()).unwrap();
//!
//! println!("{:#?}", names_element);
//! {
//!     // get first `name` element
//!     let name = names_element.get_mut_child("name").expect("Can't find name element");
//!     name.attributes.insert("suffix".to_owned(), "mr".to_owned());
//! }
//! names_element.write(File::create("result.xml").unwrap());
//!
//!
//! ```
extern crate xml;

use std::collections::HashMap;
use std::io::{Read, Write};
use std::borrow::Cow;
use std::fmt;

use xml::reader::{EventReader, XmlEvent};
pub use xml::writer::EmitterConfig;
pub use xml::namespace::Namespace;

/// Represents an XML element.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Element {
    /// This elements prefix, if any
    pub prefix: Option<String>,

    /// This elements namespace, if any
    pub namespace: Option<String>,

    /// The full list of namespaces, if any
    ///
    /// The `Namespace` type is exported from the `xml-rs` crate.
    pub namespaces: Option<Namespace>,

    /// The name of the Element.  Does not include any namespace info
    pub name: String,

    /// The Element attributes
    pub attributes: HashMap<String, String>,

    /// Children
    pub children: Vec<Element>,

    /// The text data for this element
    pub text: Option<String>,
}

/// Errors that can occur parsing XML
#[derive(Debug)]
pub enum ParseError {
    /// The XML is invalid
    MalformedXml(xml::reader::Error),
    /// This library is unable to process this XML. This can occur if, for
    /// example, the XML contains processing instructions.
    CannotParse,
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseError::MalformedXml(ref e) => write!(f, "Malformed XML. {}", e),
            ParseError::CannotParse => write!(f, "Cannot parse"),
        }
    }
}

impl std::error::Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::MalformedXml(..) => "Malformed XML",
            ParseError::CannotParse => "Cannot parse",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            ParseError::MalformedXml(ref e) => Some(e),
            ParseError::CannotParse => None,
        }
    }
}

fn build<B: Read>(reader: &mut EventReader<B>, mut elem: Element) -> Result<Element, ParseError> {
    loop {
        match reader.next() {
            Ok(XmlEvent::EndElement { ref name }) => {
                if name.local_name == elem.name {
                    return Ok(elem);
                } else {
                    return Err(ParseError::CannotParse);
                }
            }
            Ok(XmlEvent::StartElement { name, attributes, namespace }) => {
                let mut attr_map = HashMap::new();
                for attr in attributes {
                    attr_map.insert(attr.name.local_name, attr.value);
                }

                let new_elem = Element {
                    prefix: name.prefix,
                    namespace: name.namespace,
                    namespaces: if namespace.is_essentially_empty() {
                        None
                    } else {
                        Some(namespace)
                    },
                    name: name.local_name,
                    attributes: attr_map,
                    children: Vec::new(),
                    text: None,
                };
                elem.children.push(try!(build(reader, new_elem)));
            }
            Ok(XmlEvent::Characters(s)) => {
                elem.text = Some(s);
            }
            Ok(XmlEvent::Whitespace(..)) | Ok(XmlEvent::Comment(..))=> (),
            Ok(XmlEvent::CData(s)) => elem.text = Some(s),
            Ok(XmlEvent::StartDocument { .. }) |
            Ok(XmlEvent::EndDocument) |
            Ok(XmlEvent::ProcessingInstruction { .. }) => return Err(ParseError::CannotParse),
            Err(e) => return Err(ParseError::MalformedXml(e)),
        }
    }

}

impl Element {
    /// Create a new empty element with given name
    ///
    /// All other fields are empty
    pub fn new(name: &str) -> Element {
        Element {
            name: String::from(name),
            prefix: None,
            namespace: None,
            namespaces: None,
            attributes: HashMap::new(),
            children: Vec::new(),
            text: None,
        }
    }

    /// Parses some data into an Element
    pub fn parse<R: Read>(r: R) -> Result<Element, ParseError> {
        let mut reader = EventReader::new(r);
        loop {
            match reader.next() {
                Ok(XmlEvent::StartElement { name, attributes, namespace }) => {
                    let mut attr_map = HashMap::new();
                    for attr in attributes {
                        attr_map.insert(attr.name.local_name, attr.value);
                    }

                    let root = Element {
                        prefix: name.prefix,
                        namespace: name.namespace,
                        namespaces: if namespace.is_essentially_empty() {
                            None
                        } else {
                            Some(namespace)
                        },
                        name: name.local_name,
                        attributes: attr_map,
                        children: Vec::new(),
                        text: None,
                    };
                    return build(&mut reader, root);
                }
                Ok(XmlEvent::Comment(..)) |
                Ok(XmlEvent::Whitespace(..)) |
                Ok(XmlEvent::StartDocument { .. }) => continue,
                Ok(XmlEvent::EndDocument) |
                Ok(XmlEvent::EndElement { .. }) |
                Ok(XmlEvent::Characters(..)) |
                Ok(XmlEvent::CData(..)) |
                Ok(XmlEvent::ProcessingInstruction { .. }) => return Err(ParseError::CannotParse),
                Err(e) => return Err(ParseError::MalformedXml(e)),
            }
        }
    }

    fn _write<B: Write>(&self, emitter: &mut xml::writer::EventWriter<B>) {
        use xml::writer::events::XmlEvent;
        use xml::name::Name;
        use xml::namespace::Namespace;
        use xml::attribute::Attribute;

        let mut name = Name::local(&self.name);
        if let Some(ref ns) = self.namespace {
            name.namespace = Some(ns);
        }
        if let Some(ref p) = self.prefix {
            name.prefix = Some(p);
        }

        let mut attributes = Vec::with_capacity(self.attributes.len());
        for (k, v) in &self.attributes {
            attributes.push(Attribute {
                                name: Name::local(k),
                                value: v,
                            });
        }

        let empty_ns = Namespace::empty();
        let namespace = if let Some(ref ns) = self.namespaces {
            Cow::Borrowed(ns)
        } else {
            Cow::Borrowed(&empty_ns)
        };

        emitter.write(XmlEvent::StartElement {
                          name: name,
                          attributes: Cow::Owned(attributes),
                          namespace: namespace,
                      })
            .unwrap();
        if let Some(ref t) = self.text {
            emitter.write(XmlEvent::Characters(t)).unwrap();
        }
        for elem in &self.children {
            elem._write(emitter);
        }
        emitter.write(XmlEvent::EndElement { name: Some(name) }).unwrap();
    }

    /// Writes out this element as the root element in an new XML document
    pub fn write<W: Write>(&self, w: W) {
        self.write_with_config(w, EmitterConfig::new())
    }

    /// Writes out this element as the root element in a new XML document using the provided configuration
    pub fn write_with_config<W: Write>(&self, w: W, config: EmitterConfig) {
        use xml::writer::EventWriter;
        use xml::writer::events::XmlEvent;
        use xml::common::XmlVersion;

        let mut emitter = EventWriter::new_with_config(w, config);
        emitter.write(XmlEvent::StartDocument {
                          version: XmlVersion::Version10,
                          encoding: None,
                          standalone: None,
                      })
            .unwrap();
        self._write(&mut emitter);
    }

    /// Find a child element with the given name and return a reference to it.
    pub fn get_child<K>(&self, k: K) -> Option<&Element>
        where String: PartialEq<K>
    {
        self.children.iter().find(|e| e.name == k)
    }

    /// Find a child element with the given name and return a mutable reference to it.
    pub fn get_mut_child<K>(&mut self, k: K) -> Option<&mut Element>
        where String: PartialEq<K>
    {
        self.children.iter_mut().find(|e| e.name == k)
    }

    /// Find a child element with the given name, remove and return it.
    pub fn take_child<K>(&mut self, k: K) -> Option<Element>
        where String: PartialEq<K>
    {
        self.children
            .iter()
            .position(|e| e.name == k)
            .map(|i| self.children.remove(i))
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate poet_sys;

use libc::{c_void, c_int, c_uint};
use std::ffi::CString;
use std::ptr;
use poet_sys::*;

pub extern fn apply_cpu_config_wrapper(states: *mut c_void,
                                       num_states: c_uint,
                                       id: c_uint,
                                       last_id: c_uint) {
    unsafe {
        apply_cpu_config(states, num_states, id, last_id)
    }
}

pub extern fn get_current_cpu_state_wrapper(states: *const c_void,
                                            num_states: c_uint,
                                            curr_state_id: *mut c_uint) -> c_int {
    unsafe {
        get_current_cpu_state(states, num_states, curr_state_id)
    }
}

pub fn default_poet_control_state_t() -> poet_control_state_t {
	poet_control_state_t {
        id: 0,
        speedup: 1.0,
        cost: 1.0,
    }
}

pub fn default_poet_cpu_state_t() -> poet_cpu_state_t {
	poet_cpu_state_t {
        id: 0,
        freq: 0,
        cores: 0,
    }
}

/// Attempt to load control states from a file.
pub fn poet_get_control_states(filename: Option<&CString>) -> Result<Vec<poet_control_state_t>, &'static str> {
    let name_ptr = match filename {
        Some(f) => f.as_ptr(),
        None => ptr::null(),
    };
    let mut states: *mut poet_control_state_t = ptr::null_mut::<poet_control_state_t>();
    let mut nstates: u32 = 0;
    if unsafe { get_control_states(name_ptr, &mut states, &mut nstates) } != 0 {
        return Err("Failed to load control states");
    }
    let mut ret: Vec<poet_control_state_t> = Vec::with_capacity(nstates as usize);
    // copy so we can free C-allocated memory
    unsafe {
        ret.set_len(nstates as usize);
        ptr::copy_nonoverlapping(states, ret.as_mut_ptr(), nstates as usize);
        libc::free(states as *mut c_void);
    }
    Ok(ret)
}

/// Attempt to load cpu states from a file.
pub fn poet_get_cpu_states(filename: Option<&CString>) -> Result<Vec<poet_cpu_state_t>, &'static str> {
    let name_ptr = match filename {
        Some(f) => f.as_ptr(),
        None => ptr::null(),
    };
    let mut states: *mut poet_cpu_state_t = ptr::null_mut::<poet_cpu_state_t>();
    let mut nstates: u32 = 0;
    if unsafe { get_cpu_states(name_ptr, &mut states, &mut nstates) } != 0 {
        return Err("Failed to load cpu states");
    }
    // copy so we can free C-allocated memory
    let mut ret: Vec<poet_cpu_state_t> = Vec::with_capacity(nstates as usize);
    unsafe {
        ret.set_len(nstates as usize);
        ptr::copy_nonoverlapping(states, ret.as_mut_ptr(), nstates as usize);
        libc::free(states as *mut c_void);
    }
    Ok(ret)
}

/// The `POET` struct wraps an underyling C struct.
pub struct POET {
    /// The underlying C struct `poet_state`.
    pub poet: *mut poet_state,
    pub control_states: Vec<poet_control_state_t>,
    pub cpu_states: Vec<poet_cpu_state_t>
}

impl POET {
    /// Attempt to initialize POET and allocate resources in the underlying C struct.
    pub fn new(perf_goal: f64,
               mut control_states: Vec<poet_control_state_t>,
               mut cpu_states: Vec<poet_cpu_state_t>,
               apply_func: poet_apply_func,
               curr_state_func: poet_curr_state_func,
               period: u32,
               buffer_depth: u32,
               log_filename: Option<&CString>) -> Result<POET, &'static str> {
        if control_states.len() != cpu_states.len() {
            return Err("Number of control and cpu states don't match");
        }
        let log_ptr = match log_filename {
            Some(l) => l.as_ptr(),
            None => ptr::null(),
        };
        let poet = unsafe {
            poet_init(perf_goal,
                      control_states.len() as c_uint, control_states.as_mut_ptr(), cpu_states.as_mut_ptr(),
                      apply_func, curr_state_func,
                      period, buffer_depth, log_ptr)
        };
        if poet.is_null() {
            return Err("Failed to instantiate POET object");
        }
        Ok(POET {
        	poet: poet,
        	control_states: control_states,
        	cpu_states: cpu_states,
        })
    }

    /// Call at every iteration - at specified periods this function will (potentially) order
    /// changes to system or application state to try and meet timing constraints.
    pub fn apply_control(&mut self, tag: u64, window_rate: f64, window_power: f64) {
        unsafe {
            poet_apply_control(self.poet, tag, window_rate, window_power);
        }
    }
}

impl Drop for POET {
    /// Cleanup POET and deallocate resources in the underlying C struct.
    fn drop(&mut self) {
        unsafe {
            poet_destroy(self.poet);
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libc::{c_void, c_uint};
    use std::ffi::CString;

    #[test]
    fn test_basic() {
        let control_states = vec![default_poet_control_state_t()];
        let cpu_states = vec![default_poet_cpu_state_t()];
        let mut poet = POET::new(100.0,
                                 control_states, cpu_states,
                                 None, None,
                                 20u32, 1u32, None).unwrap();
        poet.apply_control(0, 1.0, 1.0);
    }

    #[test]
    fn test_control_cpu_files_with_log() {
        let control_states = poet_get_control_states(Some(&CString::new("test/control_config").unwrap())).unwrap();
        let cpu_states = poet_get_cpu_states(Some(&CString::new("test/cpu_config").unwrap())).unwrap();
        let mut poet = POET::new(100.0,
                                 control_states, cpu_states,
                                 None, None,
                                 20u32, 1u32, Some(&CString::new("poet.log").unwrap())).unwrap();
        poet.apply_control(0, 1.0, 1.0);
    }

    #[test]
    fn test_rust_callbacks() {
        let control_states = vec![default_poet_control_state_t()];
        let cpu_states = vec![default_poet_cpu_state_t()];
        let mut poet = POET::new(100.0,
                                 control_states, cpu_states,
                                 Some(dummy_apply), Some(dummy_curr_state),
                                 20u32, 1u32, None).unwrap();
        for i in 0..50 {
            poet.apply_control(i, 1.0, 1.0);
        }
    }

    extern fn dummy_apply(_states: *mut c_void,
                          _num_states: c_uint,
                          _id: c_uint,
                          _last_id: c_uint) {
        // do nothing
        println!("Received apply call");
    }

    extern fn dummy_curr_state(_states: *const c_void,
                               _num_states: c_uint,
                               _curr_state_id: *mut c_uint) -> i32 {
        println!("Received curr state call");
        unsafe {
            // this is actually an invalid value, but forces the apply function to be called
            *_curr_state_id = _num_states;
        }
        0
    }

}
<commit_msg>Add function set_performance_goal<commit_after>extern crate libc;
extern crate poet_sys;

use libc::{c_void, c_int, c_uint};
use std::ffi::CString;
use std::ptr;
use poet_sys::*;

pub extern fn apply_cpu_config_wrapper(states: *mut c_void,
                                       num_states: c_uint,
                                       id: c_uint,
                                       last_id: c_uint) {
    unsafe {
        apply_cpu_config(states, num_states, id, last_id)
    }
}

pub extern fn get_current_cpu_state_wrapper(states: *const c_void,
                                            num_states: c_uint,
                                            curr_state_id: *mut c_uint) -> c_int {
    unsafe {
        get_current_cpu_state(states, num_states, curr_state_id)
    }
}

pub fn default_poet_control_state_t() -> poet_control_state_t {
	poet_control_state_t {
        id: 0,
        speedup: 1.0,
        cost: 1.0,
    }
}

pub fn default_poet_cpu_state_t() -> poet_cpu_state_t {
	poet_cpu_state_t {
        id: 0,
        freq: 0,
        cores: 0,
    }
}

/// Attempt to load control states from a file.
pub fn poet_get_control_states(filename: Option<&CString>) -> Result<Vec<poet_control_state_t>, &'static str> {
    let name_ptr = match filename {
        Some(f) => f.as_ptr(),
        None => ptr::null(),
    };
    let mut states: *mut poet_control_state_t = ptr::null_mut::<poet_control_state_t>();
    let mut nstates: u32 = 0;
    if unsafe { get_control_states(name_ptr, &mut states, &mut nstates) } != 0 {
        return Err("Failed to load control states");
    }
    let mut ret: Vec<poet_control_state_t> = Vec::with_capacity(nstates as usize);
    // copy so we can free C-allocated memory
    unsafe {
        ret.set_len(nstates as usize);
        ptr::copy_nonoverlapping(states, ret.as_mut_ptr(), nstates as usize);
        libc::free(states as *mut c_void);
    }
    Ok(ret)
}

/// Attempt to load cpu states from a file.
pub fn poet_get_cpu_states(filename: Option<&CString>) -> Result<Vec<poet_cpu_state_t>, &'static str> {
    let name_ptr = match filename {
        Some(f) => f.as_ptr(),
        None => ptr::null(),
    };
    let mut states: *mut poet_cpu_state_t = ptr::null_mut::<poet_cpu_state_t>();
    let mut nstates: u32 = 0;
    if unsafe { get_cpu_states(name_ptr, &mut states, &mut nstates) } != 0 {
        return Err("Failed to load cpu states");
    }
    // copy so we can free C-allocated memory
    let mut ret: Vec<poet_cpu_state_t> = Vec::with_capacity(nstates as usize);
    unsafe {
        ret.set_len(nstates as usize);
        ptr::copy_nonoverlapping(states, ret.as_mut_ptr(), nstates as usize);
        libc::free(states as *mut c_void);
    }
    Ok(ret)
}

/// The `POET` struct wraps an underyling C struct.
pub struct POET {
    /// The underlying C struct `poet_state`.
    pub poet: *mut poet_state,
    pub control_states: Vec<poet_control_state_t>,
    pub cpu_states: Vec<poet_cpu_state_t>
}

impl POET {
    /// Attempt to initialize POET and allocate resources in the underlying C struct.
    pub fn new(perf_goal: f64,
               mut control_states: Vec<poet_control_state_t>,
               mut cpu_states: Vec<poet_cpu_state_t>,
               apply_func: poet_apply_func,
               curr_state_func: poet_curr_state_func,
               period: u32,
               buffer_depth: u32,
               log_filename: Option<&CString>) -> Result<POET, &'static str> {
        if control_states.len() != cpu_states.len() {
            return Err("Number of control and cpu states don't match");
        }
        let log_ptr = match log_filename {
            Some(l) => l.as_ptr(),
            None => ptr::null(),
        };
        let poet = unsafe {
            poet_init(perf_goal,
                      control_states.len() as c_uint, control_states.as_mut_ptr(), cpu_states.as_mut_ptr(),
                      apply_func, curr_state_func,
                      period, buffer_depth, log_ptr)
        };
        if poet.is_null() {
            return Err("Failed to instantiate POET object");
        }
        Ok(POET {
        	poet: poet,
        	control_states: control_states,
        	cpu_states: cpu_states,
        })
    }

    /// Call at every iteration - at specified periods this function will (potentially) order
    /// changes to system or application state to try and meet timing constraints.
    pub fn apply_control(&mut self, tag: u64, window_rate: f64, window_power: f64) {
        unsafe {
            poet_apply_control(self.poet, tag, window_rate, window_power);
        }
    }

    /// Change the performance goal.
    pub fn set_performance_goal(&mut self, perf_goal: f64) {
        unsafe {
            poet_set_performance_goal(self.poet, perf_goal);
        }
    }
}

impl Drop for POET {
    /// Cleanup POET and deallocate resources in the underlying C struct.
    fn drop(&mut self) {
        unsafe {
            poet_destroy(self.poet);
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libc::{c_void, c_uint};
    use std::ffi::CString;

    #[test]
    fn test_basic() {
        let control_states = vec![default_poet_control_state_t()];
        let cpu_states = vec![default_poet_cpu_state_t()];
        let mut poet = POET::new(100.0,
                                 control_states, cpu_states,
                                 None, None,
                                 20u32, 1u32, None).unwrap();
        poet.set_performance_goal(200.0);
        poet.apply_control(0, 1.0, 1.0);
    }

    #[test]
    fn test_control_cpu_files_with_log() {
        let control_states = poet_get_control_states(Some(&CString::new("test/control_config").unwrap())).unwrap();
        let cpu_states = poet_get_cpu_states(Some(&CString::new("test/cpu_config").unwrap())).unwrap();
        let mut poet = POET::new(100.0,
                                 control_states, cpu_states,
                                 None, None,
                                 20u32, 1u32, Some(&CString::new("poet.log").unwrap())).unwrap();
        poet.apply_control(0, 1.0, 1.0);
    }

    #[test]
    fn test_rust_callbacks() {
        let control_states = vec![default_poet_control_state_t()];
        let cpu_states = vec![default_poet_cpu_state_t()];
        let mut poet = POET::new(100.0,
                                 control_states, cpu_states,
                                 Some(dummy_apply), Some(dummy_curr_state),
                                 20u32, 1u32, None).unwrap();
        for i in 0..50 {
            poet.apply_control(i, 1.0, 1.0);
        }
    }

    extern fn dummy_apply(_states: *mut c_void,
                          _num_states: c_uint,
                          _id: c_uint,
                          _last_id: c_uint) {
        // do nothing
        println!("Received apply call");
    }

    extern fn dummy_curr_state(_states: *const c_void,
                               _num_states: c_uint,
                               _curr_state_id: *mut c_uint) -> i32 {
        println!("Received curr state call");
        unsafe {
            // this is actually an invalid value, but forces the apply function to be called
            *_curr_state_id = _num_states;
        }
        0
    }

}
<|endoftext|>