<commit_before>use parking_lot::Mutex;

use std::cmp::Ordering;
use std::collections::BTreeMap;

use crate::gc::Address;
use crate::vm::{CodeId, CodeKind, VM};

pub struct CodeMap {
    tree: Mutex<BTreeMap<CodeSpan, CodeId>>,
}

impl CodeMap {
    pub fn new() -> CodeMap {
        CodeMap {
            tree: Mutex::new(BTreeMap::new()),
        }
    }

    pub fn dump(&self, vm: &VM) {
        let tree = self.tree.lock();
        println!("CodeMap {{");

        for (key, &code_id) in tree.iter() {
            print!("  {} - {} => ", key.start, key.end);
            let code = vm.code.idx(code_id);

            match code.descriptor() {
                CodeKind::DoraFct(fct_id) => {
                    let fct = vm.fcts.idx(fct_id);
                    let fct = fct.read();

                    println!("dora {}", fct.name_with_params(vm));
                }
                CodeKind::CompileStub => println!("compile_stub"),
                CodeKind::TrapStub => println!("trap_stub"),
                CodeKind::AllocStub => println!("alloc_stub"),
                CodeKind::VerifyStub => println!("verify_stub"),
                CodeKind::NativeStub(fct_id) => {
                    let fct = vm.fcts.idx(fct_id);
                    let fct = fct.read();

                    println!("native stub {}", fct.name_with_params(vm));
                }
                CodeKind::DoraStub => println!("dora_stub"),
                CodeKind::GuardCheckStub => println!("guard_check_stub"),
                CodeKind::SafepointStub => println!("safepoint_stub"),
            }
        }

        println!("}}");
    }

    pub fn insert(&self, start: Address, end: Address, code_id: CodeId) {
        let mut tree = self.tree.lock();
        let span = CodeSpan::new(start, end);
        assert!(tree.insert(span, code_id).is_none());
    }

    pub fn get(&self, ptr: Address) -> Option<CodeId> {
        let tree = self.tree.lock();
        let span = CodeSpan::new(ptr, ptr.offset(1));
        tree.get(&span).map(|el| *el)
    }
}

#[derive(Copy, Clone, Debug)]
struct CodeSpan {
    start: Address,
    end: Address,
}

impl CodeSpan {
    fn intersect(&self, other: &CodeSpan) -> bool {
        (self.start <= other.start && other.start < self.end)
            || (self.start < other.end && other.end <= self.end)
            || (other.start <= self.start && self.end <= other.end)
    }
}

impl PartialEq for CodeSpan {
    fn eq(&self, other: &CodeSpan) -> bool {
        self.intersect(other)
    }
}

impl Eq for CodeSpan {}

impl PartialOrd for CodeSpan {
    fn partial_cmp(&self, other: &CodeSpan) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for CodeSpan {
    fn cmp(&self, other: &CodeSpan) -> Ordering {
        if self.intersect(other) {
            Ordering::Equal
        } else if self.start >= other.end {
            Ordering::Greater
        } else {
            Ordering::Less
        }
    }
}

impl CodeSpan {
    fn new(start: Address, end: Address) -> CodeSpan {
        assert!(start < end);

        CodeSpan { start, end }
    }
}

#[test]
#[should_panic]
fn test_new_fail() {
    span(7, 5);
}

#[test]
fn test_new() {
    span(5, 7);
}

#[test]
fn test_intersect() {
    assert!(span(5, 7).intersect(&span(1, 6)));
    assert!(!span(5, 7).intersect(&span(1, 5)));
    assert!(span(5, 7).intersect(&span(5, 7)));
    assert!(span(5, 7).intersect(&span(4, 7)));
    assert!(!span(5, 7).intersect(&span(7, 9)));
    assert!(!span(5, 7).intersect(&span(7, 8)));
}

#[cfg(test)]
fn span(v1: usize, v2: usize) -> CodeSpan {
    CodeSpan::new(v1.into(), v2.into())
}

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

    #[test]
    fn test_insert() {
        let map = CodeMap::new();

        map.insert(5.into(), 7.into(), 1.into());
        map.insert(7.into(), 9.into(), 2.into());

        assert_eq!(None, map.get(4.into()));
        assert_eq!(Some(1.into()), map.get(5.into()));
        assert_eq!(Some(1.into()), map.get(6.into()));
        assert_eq!(Some(2.into()), map.get(7.into()));
        assert_eq!(Some(2.into()), map.get(8.into()));
        assert_eq!(None, map.get(9.into()));
    }

    #[test]
    #[should_panic]
    fn test_insert_fails() {
        let map = CodeMap::new();

        map.insert(5.into(), 7.into(), 1.into());
        map.insert(6.into(), 7.into(), 2.into());
    }
}
<commit_msg>switch to RwLock for CodeMap<commit_after>use parking_lot::RwLock;

use std::cmp::Ordering;
use std::collections::BTreeMap;

use crate::gc::Address;
use crate::vm::{CodeId, CodeKind, VM};

pub struct CodeMap {
    tree: RwLock<BTreeMap<CodeSpan, CodeId>>,
}

impl CodeMap {
    pub fn new() -> CodeMap {
        CodeMap {
            tree: RwLock::new(BTreeMap::new()),
        }
    }

    pub fn dump(&self, vm: &VM) {
        let tree = self.tree.read();
        println!("CodeMap {{");

        for (key, &code_id) in tree.iter() {
            print!("  {} - {} => ", key.start, key.end);
            let code = vm.code.idx(code_id);

            match code.descriptor() {
                CodeKind::DoraFct(fct_id) => {
                    let fct = vm.fcts.idx(fct_id);
                    let fct = fct.read();

                    println!("dora {}", fct.name_with_params(vm));
                }
                CodeKind::CompileStub => println!("compile_stub"),
                CodeKind::TrapStub => println!("trap_stub"),
                CodeKind::AllocStub => println!("alloc_stub"),
                CodeKind::VerifyStub => println!("verify_stub"),
                CodeKind::NativeStub(fct_id) => {
                    let fct = vm.fcts.idx(fct_id);
                    let fct = fct.read();

                    println!("native stub {}", fct.name_with_params(vm));
                }
                CodeKind::DoraStub => println!("dora_stub"),
                CodeKind::GuardCheckStub => println!("guard_check_stub"),
                CodeKind::SafepointStub => println!("safepoint_stub"),
            }
        }

        println!("}}");
    }

    pub fn insert(&self, start: Address, end: Address, code_id: CodeId) {
        let mut tree = self.tree.write();
        let span = CodeSpan::new(start, end);
        assert!(tree.insert(span, code_id).is_none());
    }

    pub fn get(&self, ptr: Address) -> Option<CodeId> {
        let tree = self.tree.read();
        let span = CodeSpan::new(ptr, ptr.offset(1));
        tree.get(&span).map(|el| *el)
    }
}

#[derive(Copy, Clone, Debug)]
struct CodeSpan {
    start: Address,
    end: Address,
}

impl CodeSpan {
    fn intersect(&self, other: &CodeSpan) -> bool {
        (self.start <= other.start && other.start < self.end)
            || (self.start < other.end && other.end <= self.end)
            || (other.start <= self.start && self.end <= other.end)
    }
}

impl PartialEq for CodeSpan {
    fn eq(&self, other: &CodeSpan) -> bool {
        self.intersect(other)
    }
}

impl Eq for CodeSpan {}

impl PartialOrd for CodeSpan {
    fn partial_cmp(&self, other: &CodeSpan) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for CodeSpan {
    fn cmp(&self, other: &CodeSpan) -> Ordering {
        if self.intersect(other) {
            Ordering::Equal
        } else if self.start >= other.end {
            Ordering::Greater
        } else {
            Ordering::Less
        }
    }
}

impl CodeSpan {
    fn new(start: Address, end: Address) -> CodeSpan {
        assert!(start < end);

        CodeSpan { start, end }
    }
}

#[test]
#[should_panic]
fn test_new_fail() {
    span(7, 5);
}

#[test]
fn test_new() {
    span(5, 7);
}

#[test]
fn test_intersect() {
    assert!(span(5, 7).intersect(&span(1, 6)));
    assert!(!span(5, 7).intersect(&span(1, 5)));
    assert!(span(5, 7).intersect(&span(5, 7)));
    assert!(span(5, 7).intersect(&span(4, 7)));
    assert!(!span(5, 7).intersect(&span(7, 9)));
    assert!(!span(5, 7).intersect(&span(7, 8)));
}

#[cfg(test)]
fn span(v1: usize, v2: usize) -> CodeSpan {
    CodeSpan::new(v1.into(), v2.into())
}

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

    #[test]
    fn test_insert() {
        let map = CodeMap::new();

        map.insert(5.into(), 7.into(), 1.into());
        map.insert(7.into(), 9.into(), 2.into());

        assert_eq!(None, map.get(4.into()));
        assert_eq!(Some(1.into()), map.get(5.into()));
        assert_eq!(Some(1.into()), map.get(6.into()));
        assert_eq!(Some(2.into()), map.get(7.into()));
        assert_eq!(Some(2.into()), map.get(8.into()));
        assert_eq!(None, map.get(9.into()));
    }

    #[test]
    #[should_panic]
    fn test_insert_fails() {
        let map = CodeMap::new();

        map.insert(5.into(), 7.into(), 1.into());
        map.insert(6.into(), 7.into(), 2.into());
    }
}
<|endoftext|>


<commit_before>use nom::{self, IResult};

use std::str;

/// list-wildcards = "%" / "*"
pub fn list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

/// quoted-specials = DQUOTE / "\"
pub fn quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

/// resp-specials = "]"
pub fn resp_specials(c: u8) -> bool {
    c == b']'
}

/// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || list_wildcards(c)
        || quoted_specials(c)
        || resp_specials(c)
}

/// ATOM-CHAR = <any CHAR except atom-specials>
pub fn atom_char(c: u8) -> bool {
    !atom_specials(c)
}

/// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn astring_char(c: u8) -> bool {
    atom_char(c) || resp_specials(c)
}

/// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

/// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, do_parse!(
    tag_s!("\"") >>
    data: quoted_data >>
    tag_s!("\"") >>
    (data)
));

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
named!(pub literal<&[u8]>, do_parse!(
    tag_s!("{") >>
    len: number >>
    tag_s!("}") >>
    tag_s!("\r\n") >>
    data: take!(len) >>
    (data)
));

/// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

/// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, map!(
    alt!(tag_s!("NIL") | string),
    |s| if s == b"NIL" { None } else { Some(s) }
));

/// number          = 1*DIGIT
///                    ; Unsigned 32-bit integer
///                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, map_res!(
    map_res!(nom::digit, str::from_utf8),
    str::parse
));

/// same as `number` but 64-bit
named!(pub number_64<u64>, map_res!(
    map_res!(nom::digit, str::from_utf8),
    str::parse
));

/// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1_s!(atom_char),
    str::from_utf8
));

/// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(astring_char) |
    string
));

/// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while_s!(text_char),
    str::from_utf8
));

/// TEXT-CHAR = <any CHAR except CR and LF>
pub fn text_char(c: u8) -> bool {
    c != b'\r' && c != b'\n'
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, "XYZ".as_bytes());
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, "text".as_bytes());
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<commit_msg>NIL only parsed as literal<commit_after>use nom::{self, IResult};

use std::str;

/// list-wildcards = "%" / "*"
pub fn list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

/// quoted-specials = DQUOTE / "\"
pub fn quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

/// resp-specials = "]"
pub fn resp_specials(c: u8) -> bool {
    c == b']'
}

/// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || list_wildcards(c)
        || quoted_specials(c)
        || resp_specials(c)
}

/// ATOM-CHAR = <any CHAR except atom-specials>
pub fn atom_char(c: u8) -> bool {
    !atom_specials(c)
}

/// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn astring_char(c: u8) -> bool {
    atom_char(c) || resp_specials(c)
}

/// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

/// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, do_parse!(
    tag_s!("\"") >>
    data: quoted_data >>
    tag_s!("\"") >>
    (data)
));

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
named!(pub literal<&[u8]>, do_parse!(
    tag_s!("{") >>
    len: number >>
    tag_s!("}") >>
    tag_s!("\r\n") >>
    data: take!(len) >>
    (data)
));

/// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

/// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, alt!(
    map!(tag_s!("NIL"), |_| None) |
    map!(string, |s| Some(s))
));

/// number          = 1*DIGIT
///                    ; Unsigned 32-bit integer
///                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, map_res!(
    map_res!(nom::digit, str::from_utf8),
    str::parse
));

/// same as `number` but 64-bit
named!(pub number_64<u64>, map_res!(
    map_res!(nom::digit, str::from_utf8),
    str::parse
));

/// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1_s!(atom_char),
    str::from_utf8
));

/// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(astring_char) |
    string
));

/// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while_s!(text_char),
    str::from_utf8
));

/// TEXT-CHAR = <any CHAR except CR and LF>
pub fn text_char(c: u8) -> bool {
    c != b'\r' && c != b'\n'
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, "XYZ".as_bytes());
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, "text".as_bytes());
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<|endoftext|>


<commit_before>extern crate proc_macro;
#[macro_use]
extern crate quote;
#[macro_use]
extern crate darling;

use syn::{Ident, Type};

use darling::{ast, FromDeriveInput};
use proc_macro::TokenStream;
use darling::export::Option;

#[derive(Debug, FromVariant)]
#[darling(from_ident, attributes(dummy))]
struct DummyVariant {
    ident: Ident,
    fields: darling::ast::Fields<DummyField>,
}

impl From<Ident> for DummyVariant {
    fn from(ident: Ident) -> Self {
        DummyVariant {
            ident,
            fields: darling::ast::Style::Unit.into(),
        }
    }
}

#[derive(Debug, FromField)]
#[darling(attributes(dummy))]
struct DummyField {
    ident: Option<Ident>,
    ty: Type,
    #[darling(default)]
    faker: Option<String>,
}

#[derive(Debug, FromDeriveInput)]
#[darling(attributes(dummy), supports(struct_any, enum_any))]
struct Dummy {
    ident: Ident,
    data: ast::Data<DummyVariant, DummyField>,
}

#[proc_macro_derive(Dummy, attributes(dummy))]
pub fn hello_world(input: TokenStream) -> TokenStream {
    let parsed = syn::parse(input).expect("syn::parse ok");
    let receiver = Dummy::from_derive_input(&parsed).expect("Dummy::from_derive_input ok");

    let receiver_name = &receiver.ident;
    let expanded = match receiver.data {
        darling::ast::Data::Struct(darling::ast::Fields {
            ref fields,
            ref style,
            ..
        }) => match style {
            ast::Style::Unit => {
                let impl_dummy = quote! {
                    impl fake::Dummy<fake::Faker> for #receiver_name {
                        fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &fake::Faker, rng: &mut R) -> Self {
                            #receiver_name
                        }
                    }
                };
                impl_dummy
            }
            ast::Style::Tuple => {
                let tuple_fields: Vec<_> = fields
                    .iter()
                    .map(|f| {
                        let field_ty = &f.ty;
                        let faker = if let Some(ref expr) = f.faker {
                            syn::parse_str::<syn::Expr>(expr).unwrap()
                        } else {
                            syn::parse_str::<syn::Expr>(&"fake::Faker").unwrap()
                        };
                        quote! {
                            (#faker).fake_with_rng::<#field_ty, _>(rng)
                        }
                    })
                    .collect();

                let impl_dummy = quote! {
                    impl fake::Dummy<fake::Faker> for #receiver_name {
                        fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &fake::Faker, rng: &mut R) -> Self {
                            #receiver_name(#(#tuple_fields),*)
                        }
                    }
                };
                impl_dummy
            }
            ast::Style::Struct => {
                let struct_fields: Vec<_> =
                    fields.iter().map(|f| f.ident.as_ref().unwrap()).collect();

                let let_statements: Vec<_> = fields
                    .iter()
                    .map(|f| {
                        let field_name = f.ident.as_ref().unwrap();
                        let field_ty = &f.ty;
                        let faker = if let Some(ref expr) = f.faker {
                            syn::parse_str::<syn::Expr>(expr).unwrap()
                        } else {
                            syn::parse_str::<syn::Expr>(&"fake::Faker").unwrap()
                        };
                        quote! {
                            let #field_name: #field_ty = (#faker).fake_with_rng(rng);
                        }
                    })
                    .collect();

                let impl_dummy = quote! {
                    impl fake::Dummy<fake::Faker> for #receiver_name {
                        fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &fake::Faker, rng: &mut R) -> Self {
                            #(#let_statements)*
                            #receiver_name {
                                #(#struct_fields),*
                            }
                        }
                    }
                };
                impl_dummy
            }
        },
        darling::ast::Data::Enum(variants) => {
            let variant_count = variants.len();
            if variant_count > 0 {
                let match_statements: Vec<_> = variants
                    .iter()
                    .enumerate()
                    .map(|(i, f)| {
                        let variant_name = &f.ident;
                        match f.fields.style {
                            ast::Style::Unit => {
                                quote! {
                                    #i => { #receiver_name::#variant_name }
                                }
                            }
                            ast::Style::Tuple => {
                                let tuple_fields: Vec<_> = f
                                    .fields
                                    .fields
                                    .iter()
                                    .map(|f| {
                                        let field_ty = &f.ty;
                                        let faker = if let Some(ref expr) = f.faker {
                                            syn::parse_str::<syn::Expr>(expr).unwrap()
                                        } else {
                                            syn::parse_str::<syn::Expr>(&"fake::Faker").unwrap()
                                        };
                                        quote! {
                                            (#faker).fake_with_rng::<#field_ty, _>(rng)
                                        }
                                    })
                                    .collect();

                                quote! {
                                    #i => {
                                        #receiver_name::#variant_name(#(#tuple_fields),*)
                                    }
                                }
                            }
                            ast::Style::Struct => {
                                let struct_fields: Vec<_> = f
                                    .fields
                                    .fields
                                    .iter()
                                    .map(|f| f.ident.as_ref().unwrap())
                                    .collect();

                                let let_statements: Vec<_> = f.fields.fields
                        .iter()
                        .map(|f| {
                            let field_name = f.ident.as_ref().unwrap();
                            let field_ty = &f.ty;
                            let faker = if let Some(ref expr) = f.faker {
                                syn::parse_str::<syn::Expr>(expr).unwrap()
                            } else {
                                syn::parse_str::<syn::Expr>(&"fake::Faker").unwrap()
                            };
                            quote! {
                                let #field_name: #field_ty = (#faker).fake_with_rng(rng);
                            }
                        })
                        .collect();

                                quote! {
                                    #i => {
                                        #(#let_statements)*
                                        #receiver_name::#variant_name {
                                            #(#struct_fields),*
                                        }
                                    }
                                }
                            }
                        }
                    })
                    .collect();

                let impl_dummy = quote! {
                    impl fake::Dummy<fake::Faker> for #receiver_name {
                        fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &fake::Faker, rng: &mut R) -> Self {
                            match rng.gen_range(0, #variant_count) {
                                #(#match_statements)*
                                _ => {
                                    unreachable!()
                                }
                            }
                        }
                    }
                };

                impl_dummy
            } else {
                let impl_dummy = quote! {
                    impl fake::Dummy<fake::Faker> for #receiver_name {
                        fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &fake::Faker, rng: &mut R) -> Self {
                            panic!("can not create an empty enum")
                        }
                    }
                };

                impl_dummy
            }
        }
    };
    expanded.into()
}
<commit_msg>add zh_cn locale<commit_after>extern crate proc_macro;
#[macro_use]
extern crate quote;
#[macro_use]
extern crate darling;

use syn::{Ident, Type};

use darling::{ast, FromDeriveInput};
use proc_macro::TokenStream;

#[derive(Debug, FromVariant)]
#[darling(from_ident, attributes(dummy))]
struct DummyVariant {
    ident: Ident,
    fields: darling::ast::Fields<DummyField>,
}

impl From<Ident> for DummyVariant {
    fn from(ident: Ident) -> Self {
        DummyVariant {
            ident,
            fields: darling::ast::Style::Unit.into(),
        }
    }
}

#[derive(Debug, FromField)]
#[darling(attributes(dummy))]
struct DummyField {
    ident: Option<Ident>,
    ty: Type,
    #[darling(default)]
    faker: Option<String>,
}

#[derive(Debug, FromDeriveInput)]
#[darling(attributes(dummy), supports(struct_any, enum_any))]
struct Dummy {
    ident: Ident,
    data: ast::Data<DummyVariant, DummyField>,
}

#[proc_macro_derive(Dummy, attributes(dummy))]
pub fn hello_world(input: TokenStream) -> TokenStream {
    let parsed = syn::parse(input).expect("syn::parse ok");
    let receiver = Dummy::from_derive_input(&parsed).expect("Dummy::from_derive_input ok");

    let receiver_name = &receiver.ident;
    let expanded = match receiver.data {
        darling::ast::Data::Struct(darling::ast::Fields {
            ref fields,
            ref style,
            ..
        }) => match style {
            ast::Style::Unit => {
                let impl_dummy = quote! {
                    impl fake::Dummy<fake::Faker> for #receiver_name {
                        fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &fake::Faker, rng: &mut R) -> Self {
                            #receiver_name
                        }
                    }
                };
                impl_dummy
            }
            ast::Style::Tuple => {
                let tuple_fields: Vec<_> = fields
                    .iter()
                    .map(|f| {
                        let field_ty = &f.ty;
                        let faker = if let Some(ref expr) = f.faker {
                            syn::parse_str::<syn::Expr>(expr).unwrap()
                        } else {
                            syn::parse_str::<syn::Expr>(&"fake::Faker").unwrap()
                        };
                        quote! {
                            (#faker).fake_with_rng::<#field_ty, _>(rng)
                        }
                    })
                    .collect();

                let impl_dummy = quote! {
                    impl fake::Dummy<fake::Faker> for #receiver_name {
                        fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &fake::Faker, rng: &mut R) -> Self {
                            #receiver_name(#(#tuple_fields),*)
                        }
                    }
                };
                impl_dummy
            }
            ast::Style::Struct => {
                let struct_fields: Vec<_> =
                    fields.iter().map(|f| f.ident.as_ref().unwrap()).collect();

                let let_statements: Vec<_> = fields
                    .iter()
                    .map(|f| {
                        let field_name = f.ident.as_ref().unwrap();
                        let field_ty = &f.ty;
                        let faker = if let Some(ref expr) = f.faker {
                            syn::parse_str::<syn::Expr>(expr).unwrap()
                        } else {
                            syn::parse_str::<syn::Expr>(&"fake::Faker").unwrap()
                        };
                        quote! {
                            let #field_name: #field_ty = (#faker).fake_with_rng(rng);
                        }
                    })
                    .collect();

                let impl_dummy = quote! {
                    impl fake::Dummy<fake::Faker> for #receiver_name {
                        fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &fake::Faker, rng: &mut R) -> Self {
                            #(#let_statements)*
                            #receiver_name {
                                #(#struct_fields),*
                            }
                        }
                    }
                };
                impl_dummy
            }
        },
        darling::ast::Data::Enum(variants) => {
            let variant_count = variants.len();
            if variant_count > 0 {
                let match_statements: Vec<_> = variants
                    .iter()
                    .enumerate()
                    .map(|(i, f)| {
                        let variant_name = &f.ident;
                        match f.fields.style {
                            ast::Style::Unit => {
                                quote! {
                                    #i => { #receiver_name::#variant_name }
                                }
                            }
                            ast::Style::Tuple => {
                                let tuple_fields: Vec<_> = f
                                    .fields
                                    .fields
                                    .iter()
                                    .map(|f| {
                                        let field_ty = &f.ty;
                                        let faker = if let Some(ref expr) = f.faker {
                                            syn::parse_str::<syn::Expr>(expr).unwrap()
                                        } else {
                                            syn::parse_str::<syn::Expr>(&"fake::Faker").unwrap()
                                        };
                                        quote! {
                                            (#faker).fake_with_rng::<#field_ty, _>(rng)
                                        }
                                    })
                                    .collect();

                                quote! {
                                    #i => {
                                        #receiver_name::#variant_name(#(#tuple_fields),*)
                                    }
                                }
                            }
                            ast::Style::Struct => {
                                let struct_fields: Vec<_> = f
                                    .fields
                                    .fields
                                    .iter()
                                    .map(|f| f.ident.as_ref().unwrap())
                                    .collect();

                                let let_statements: Vec<_> = f.fields.fields
                        .iter()
                        .map(|f| {
                            let field_name = f.ident.as_ref().unwrap();
                            let field_ty = &f.ty;
                            let faker = if let Some(ref expr) = f.faker {
                                syn::parse_str::<syn::Expr>(expr).unwrap()
                            } else {
                                syn::parse_str::<syn::Expr>(&"fake::Faker").unwrap()
                            };
                            quote! {
                                let #field_name: #field_ty = (#faker).fake_with_rng(rng);
                            }
                        })
                        .collect();

                                quote! {
                                    #i => {
                                        #(#let_statements)*
                                        #receiver_name::#variant_name {
                                            #(#struct_fields),*
                                        }
                                    }
                                }
                            }
                        }
                    })
                    .collect();

                let impl_dummy = quote! {
                    impl fake::Dummy<fake::Faker> for #receiver_name {
                        fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &fake::Faker, rng: &mut R) -> Self {
                            match rng.gen_range(0, #variant_count) {
                                #(#match_statements)*
                                _ => {
                                    unreachable!()
                                }
                            }
                        }
                    }
                };

                impl_dummy
            } else {
                let impl_dummy = quote! {
                    impl fake::Dummy<fake::Faker> for #receiver_name {
                        fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &fake::Faker, rng: &mut R) -> Self {
                            panic!("can not create an empty enum")
                        }
                    }
                };

                impl_dummy
            }
        }
    };
    expanded.into()
}
<|endoftext|>


<commit_before>//! fixed-point numerical types

use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};

// shared between Fixed and F2Dot14
macro_rules! fixed_impl {
    ($name:ident, $bits:literal, $fract_bits:literal, $ty:ty) => {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
        #[doc = concat!(stringify!($bits), "-bit signed fixed point number with ", stringify!($fract_bits), " bits of fraction." )]
        pub struct $name($ty);
        impl $name {
            /// Minimum value.
            pub const MIN: Self = Self(<$ty>::MIN);

            /// Maximum value.
            pub const MAX: Self = Self(<$ty>::MAX);

            /// This type's smallest representable value
            pub const EPSILON: Self = Self(1);

            const INT_MASK: $ty = !0 << $fract_bits;
            const ROUND: $ty = 1 << ($fract_bits - 1);
            const ONE: $ty = 1 << $fract_bits;
            const FRACT_BITS: usize = $fract_bits;

            //TODO: is this actually useful?
            /// Returns the nearest integer value.
            pub fn round(self) -> Self {
                Self(self.0.wrapping_add(Self::ROUND) & Self::INT_MASK)
            }

            /// Returns the absolute value of the number.
            pub fn abs(self) -> Self {
                Self(self.0.abs())
            }

            /// Returns the largest integer less than or equal to the number.
            pub fn floor(self) -> Self {
                Self(self.0 & Self::INT_MASK)
            }

            /// Returns the fractional part of the number.
            pub fn fract(self) -> Self {
                Self(self.0 - self.floor().0)
            }

            /// Wrapping addition.
            pub fn wrapping_add(self, other: Self) -> Self {
                Self(self.0.wrapping_add(other.0))
            }

            /// Saturating addition.
            pub fn saturating_add(self, other: Self) -> Self {
                Self(self.0.saturating_add(other.0))
            }

            /// Wrapping substitution.
            pub fn wrapping_sub(self, other: Self) -> Self {
                Self(self.0.wrapping_sub(other.0))
            }

            /// Saturating substitution.
            pub fn saturating_sub(self, other: Self) -> Self {
                Self(self.0.saturating_sub(other.0))
            }

            /// The representation of this number as a big-endian byte array.
            pub fn to_be_bytes(self) -> [u8; $bits / 8] {
                self.0.to_be_bytes()
            }
        }

        impl Add for $name {
            type Output = Self;
            #[inline(always)]
            fn add(self, other: Self) -> Self {
                // same overflow semantics as std: panic in debug, wrap in release
                Self(self.0 + other.0)
            }
        }

        impl AddAssign for $name {
            fn add_assign(&mut self, other: Self) {
                *self = *self + other;
            }
        }

        impl Sub for $name {
            type Output = Self;
            #[inline(always)]
            fn sub(self, other: Self) -> Self {
                Self(self.0 - other.0)
            }
        }

        impl SubAssign for $name {
            fn sub_assign(&mut self, other: Self) {
                *self = *self - other;
            }
        }
    };
}

/// impl float conversion methods.
///
/// We convert to different float types in order to ensure we can roundtrip
/// without floating point error.
macro_rules! float_conv {
    ($name:ident, $to:ident, $from:ident, $ty:ty) => {
        impl $name {
            #[doc = concat!("Creates a fixed point value from a", stringify!($ty), ".")]
            ///
            /// This operation is lossy; the float will be rounded to the nearest
            /// representable value.
            pub fn $from(x: $ty) -> Self {
                #[cfg(any(feature = "std", test))]
                return Self((x * Self::ONE as $ty).round() as _);
                //NOTE: this behaviour is not exactly equivalent, but should be okay?
                //what matters is that we are rounding *away from zero*.
                #[cfg(all(not(feature = "std"), not(test)))]
                Self(
                    (x * Self::ONE as $ty + (0.5 * (-1.0 * x.is_sign_negative() as u8 as $ty)))
                        as _,
                )
            }

            #[doc = concat!("Returns the value as an ", stringify!($ty), ".")]
            ///
            /// This operation is lossless: all representable values can be
            /// round-tripped.
            pub fn $to(self) -> $ty {
                let int = ((self.0 & Self::INT_MASK) >> Self::FRACT_BITS) as $ty;
                let fract = (self.0 & !Self::INT_MASK) as $ty / Self::ONE as $ty;
                int + fract
            }
        }

        //hack: we can losslessly go to float, so use those fmt impls
        impl std::fmt::Display for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                self.$to().fmt(f)
            }
        }

        impl std::fmt::Debug for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                self.$to().fmt(f)
            }
        }
    };
}

fixed_impl!(F2Dot14, 16, 14, i16);
fixed_impl!(Fixed, 32, 16, i32);
float_conv!(F2Dot14, to_f32, from_f32, f32);
float_conv!(Fixed, to_f64, from_f64, f64);
crate::newtype_scalar!(F2Dot14, [u8; 2]);
crate::newtype_scalar!(Fixed, [u8; 4]);

impl F2Dot14 {
    /// Converts a 2.14 to 16.16 fixed point value.
    pub fn to_fixed(&self) -> Fixed {
        Fixed(self.0 as i32 * 4)
    }
}

impl Mul for Fixed {
    type Output = Self;
    #[inline(always)]
    fn mul(self, other: Self) -> Self::Output {
        let ab = self.0 as i64 * other.0 as i64;
        Self(((ab + 0x8000 - if ab < 0 { 1 } else { 0 }) >> 16) as i32)
    }
}

impl MulAssign for Fixed {
    fn mul_assign(&mut self, rhs: Self) {
        *self = *self * rhs;
    }
}

impl Div for Fixed {
    type Output = Self;
    #[inline(always)]
    fn div(self, other: Self) -> Self::Output {
        let mut sign = 1;
        let mut a = self.0;
        let mut b = other.0;
        if a < 0 {
            a = -a;
            sign = -1;
        }
        if b < 0 {
            b = -b;
            sign = -sign;
        }
        let q = if b == 0 {
            0x7FFFFFFF
        } else {
            ((((a as u64) << 16) + ((b as u64) >> 1)) / (b as u64)) as u32
        };
        Self(if sign < 0 { -(q as i32) } else { q as i32 })
    }
}

impl DivAssign for Fixed {
    fn div_assign(&mut self, rhs: Self) {
        *self = *self / rhs;
    }
}

impl Neg for Fixed {
    type Output = Self;
    #[inline(always)]
    fn neg(self) -> Self {
        Self(-self.0)
    }
}

#[cfg(test)]
mod tests {
    #![allow(overflowing_literals)] // we want to specify byte values directly
    use super::*;

    #[test]
    fn f2dot14_floats() {
        // Examples from https://docs.microsoft.com/en-us/typography/opentype/spec/otff#data-types
        assert_eq!(F2Dot14(0x7fff), F2Dot14::from_f32(1.999939));
        assert_eq!(F2Dot14(0x7000), F2Dot14::from_f32(1.75));
        assert_eq!(F2Dot14(0x0001), F2Dot14::from_f32(0.0000610356));
        assert_eq!(F2Dot14(0x0000), F2Dot14::from_f32(0.0));
        assert_eq!(F2Dot14(0xffff), F2Dot14::from_f32(-0.000061));
        assert_eq!(F2Dot14(0x8000), F2Dot14::from_f32(-2.0));
    }

    #[test]
    fn roundtrip_f2dot14() {
        for i in i16::MIN..=i16::MAX {
            let val = F2Dot14(i);
            assert_eq!(val, F2Dot14::from_f32(val.to_f32()));
        }
    }

    #[test]
    fn round_f2dot14() {
        assert_eq!(F2Dot14(0x7000).round(), F2Dot14::from_f32(-2.0));
        assert_eq!(F2Dot14(0x1F00).round(), F2Dot14::from_f32(0.0));
        assert_eq!(F2Dot14(0x2000).round(), F2Dot14::from_f32(1.0));
    }

    #[test]
    fn round_fixed() {
        //TODO: make good test cases
        assert_eq!(Fixed(0x0001_7FFE).round(), Fixed(0x0001_0000));
        assert_eq!(Fixed(0x0001_7FFF).round(), Fixed(0x0001_0000));
        assert_eq!(Fixed(0x0001_8000).round(), Fixed(0x0002_0000));
    }

    // disabled because it's slow; these were just for my edification anyway
    //#[test]
    //fn roundtrip_fixed() {
    //for i in i32::MIN..=i32::MAX {
    //let val = Fixed(i);
    //assert_eq!(val, Fixed::from_f64(val.to_f64()));
    //}
    //}

    #[test]
    fn fixed_floats() {
        assert_eq!(Fixed(0x7fff_0000), Fixed::from_f64(32767.));
        assert_eq!(Fixed(0x7000_0001), Fixed::from_f64(28672.00001525879));
        assert_eq!(Fixed(0x0001_0000), Fixed::from_f64(1.0));
        assert_eq!(Fixed(0x0000_0000), Fixed::from_f64(0.0));
        assert_eq!(
            Fixed(i32::from_be_bytes([0xff; 4])),
            Fixed::from_f64(-0.000015259)
        );
        assert_eq!(Fixed(0x7fff_ffff), Fixed::from_f64(32768.0));
    }
}
<commit_msg>clever clippy<commit_after>//! fixed-point numerical types

use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};

// shared between Fixed and F2Dot14
macro_rules! fixed_impl {
    ($name:ident, $bits:literal, $fract_bits:literal, $ty:ty) => {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
        #[doc = concat!(stringify!($bits), "-bit signed fixed point number with ", stringify!($fract_bits), " bits of fraction." )]
        pub struct $name($ty);
        impl $name {
            /// Minimum value.
            pub const MIN: Self = Self(<$ty>::MIN);

            /// Maximum value.
            pub const MAX: Self = Self(<$ty>::MAX);

            /// This type's smallest representable value
            pub const EPSILON: Self = Self(1);

            const INT_MASK: $ty = !0 << $fract_bits;
            const ROUND: $ty = 1 << ($fract_bits - 1);
            const ONE: $ty = 1 << $fract_bits;
            const FRACT_BITS: usize = $fract_bits;

            //TODO: is this actually useful?
            /// Returns the nearest integer value.
            pub fn round(self) -> Self {
                Self(self.0.wrapping_add(Self::ROUND) & Self::INT_MASK)
            }

            /// Returns the absolute value of the number.
            pub fn abs(self) -> Self {
                Self(self.0.abs())
            }

            /// Returns the largest integer less than or equal to the number.
            pub fn floor(self) -> Self {
                Self(self.0 & Self::INT_MASK)
            }

            /// Returns the fractional part of the number.
            pub fn fract(self) -> Self {
                Self(self.0 - self.floor().0)
            }

            /// Wrapping addition.
            pub fn wrapping_add(self, other: Self) -> Self {
                Self(self.0.wrapping_add(other.0))
            }

            /// Saturating addition.
            pub fn saturating_add(self, other: Self) -> Self {
                Self(self.0.saturating_add(other.0))
            }

            /// Wrapping substitution.
            pub fn wrapping_sub(self, other: Self) -> Self {
                Self(self.0.wrapping_sub(other.0))
            }

            /// Saturating substitution.
            pub fn saturating_sub(self, other: Self) -> Self {
                Self(self.0.saturating_sub(other.0))
            }

            /// The representation of this number as a big-endian byte array.
            pub fn to_be_bytes(self) -> [u8; $bits / 8] {
                self.0.to_be_bytes()
            }
        }

        impl Add for $name {
            type Output = Self;
            #[inline(always)]
            fn add(self, other: Self) -> Self {
                // same overflow semantics as std: panic in debug, wrap in release
                Self(self.0 + other.0)
            }
        }

        impl AddAssign for $name {
            fn add_assign(&mut self, other: Self) {
                *self = *self + other;
            }
        }

        impl Sub for $name {
            type Output = Self;
            #[inline(always)]
            fn sub(self, other: Self) -> Self {
                Self(self.0 - other.0)
            }
        }

        impl SubAssign for $name {
            fn sub_assign(&mut self, other: Self) {
                *self = *self - other;
            }
        }
    };
}

/// impl float conversion methods.
///
/// We convert to different float types in order to ensure we can roundtrip
/// without floating point error.
macro_rules! float_conv {
    ($name:ident, $to:ident, $from:ident, $ty:ty) => {
        impl $name {
            #[doc = concat!("Creates a fixed point value from a", stringify!($ty), ".")]
            ///
            /// This operation is lossy; the float will be rounded to the nearest
            /// representable value.
            pub fn $from(x: $ty) -> Self {
                #[cfg(any(feature = "std", test))]
                return Self((x * Self::ONE as $ty).round() as _);
                //NOTE: this behaviour is not exactly equivalent, but should be okay?
                //what matters is that we are rounding *away from zero*.
                #[cfg(all(not(feature = "std"), not(test)))]
                Self(
                    (x * Self::ONE as $ty + (0.5 * (-1.0 * x.is_sign_negative() as u8 as $ty)))
                        as _,
                )
            }

            #[doc = concat!("Returns the value as an ", stringify!($ty), ".")]
            ///
            /// This operation is lossless: all representable values can be
            /// round-tripped.
            pub fn $to(self) -> $ty {
                let int = ((self.0 & Self::INT_MASK) >> Self::FRACT_BITS) as $ty;
                let fract = (self.0 & !Self::INT_MASK) as $ty / Self::ONE as $ty;
                int + fract
            }
        }

        //hack: we can losslessly go to float, so use those fmt impls
        impl std::fmt::Display for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                self.$to().fmt(f)
            }
        }

        impl std::fmt::Debug for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                self.$to().fmt(f)
            }
        }
    };
}

fixed_impl!(F2Dot14, 16, 14, i16);
fixed_impl!(Fixed, 32, 16, i32);
float_conv!(F2Dot14, to_f32, from_f32, f32);
float_conv!(Fixed, to_f64, from_f64, f64);
crate::newtype_scalar!(F2Dot14, [u8; 2]);
crate::newtype_scalar!(Fixed, [u8; 4]);

impl F2Dot14 {
    /// Converts a 2.14 to 16.16 fixed point value.
    pub fn to_fixed(&self) -> Fixed {
        Fixed(self.0 as i32 * 4)
    }
}

impl Mul for Fixed {
    type Output = Self;
    #[inline(always)]
    fn mul(self, other: Self) -> Self::Output {
        let ab = self.0 as i64 * other.0 as i64;
        Self(((ab + 0x8000 - i64::from(ab < 0)) >> 16) as i32)
    }
}

impl MulAssign for Fixed {
    fn mul_assign(&mut self, rhs: Self) {
        *self = *self * rhs;
    }
}

impl Div for Fixed {
    type Output = Self;
    #[inline(always)]
    fn div(self, other: Self) -> Self::Output {
        let mut sign = 1;
        let mut a = self.0;
        let mut b = other.0;
        if a < 0 {
            a = -a;
            sign = -1;
        }
        if b < 0 {
            b = -b;
            sign = -sign;
        }
        let q = if b == 0 {
            0x7FFFFFFF
        } else {
            ((((a as u64) << 16) + ((b as u64) >> 1)) / (b as u64)) as u32
        };
        Self(if sign < 0 { -(q as i32) } else { q as i32 })
    }
}

impl DivAssign for Fixed {
    fn div_assign(&mut self, rhs: Self) {
        *self = *self / rhs;
    }
}

impl Neg for Fixed {
    type Output = Self;
    #[inline(always)]
    fn neg(self) -> Self {
        Self(-self.0)
    }
}

#[cfg(test)]
mod tests {
    #![allow(overflowing_literals)] // we want to specify byte values directly
    use super::*;

    #[test]
    fn f2dot14_floats() {
        // Examples from https://docs.microsoft.com/en-us/typography/opentype/spec/otff#data-types
        assert_eq!(F2Dot14(0x7fff), F2Dot14::from_f32(1.999939));
        assert_eq!(F2Dot14(0x7000), F2Dot14::from_f32(1.75));
        assert_eq!(F2Dot14(0x0001), F2Dot14::from_f32(0.0000610356));
        assert_eq!(F2Dot14(0x0000), F2Dot14::from_f32(0.0));
        assert_eq!(F2Dot14(0xffff), F2Dot14::from_f32(-0.000061));
        assert_eq!(F2Dot14(0x8000), F2Dot14::from_f32(-2.0));
    }

    #[test]
    fn roundtrip_f2dot14() {
        for i in i16::MIN..=i16::MAX {
            let val = F2Dot14(i);
            assert_eq!(val, F2Dot14::from_f32(val.to_f32()));
        }
    }

    #[test]
    fn round_f2dot14() {
        assert_eq!(F2Dot14(0x7000).round(), F2Dot14::from_f32(-2.0));
        assert_eq!(F2Dot14(0x1F00).round(), F2Dot14::from_f32(0.0));
        assert_eq!(F2Dot14(0x2000).round(), F2Dot14::from_f32(1.0));
    }

    #[test]
    fn round_fixed() {
        //TODO: make good test cases
        assert_eq!(Fixed(0x0001_7FFE).round(), Fixed(0x0001_0000));
        assert_eq!(Fixed(0x0001_7FFF).round(), Fixed(0x0001_0000));
        assert_eq!(Fixed(0x0001_8000).round(), Fixed(0x0002_0000));
    }

    // disabled because it's slow; these were just for my edification anyway
    //#[test]
    //fn roundtrip_fixed() {
    //for i in i32::MIN..=i32::MAX {
    //let val = Fixed(i);
    //assert_eq!(val, Fixed::from_f64(val.to_f64()));
    //}
    //}

    #[test]
    fn fixed_floats() {
        assert_eq!(Fixed(0x7fff_0000), Fixed::from_f64(32767.));
        assert_eq!(Fixed(0x7000_0001), Fixed::from_f64(28672.00001525879));
        assert_eq!(Fixed(0x0001_0000), Fixed::from_f64(1.0));
        assert_eq!(Fixed(0x0000_0000), Fixed::from_f64(0.0));
        assert_eq!(
            Fixed(i32::from_be_bytes([0xff; 4])),
            Fixed::from_f64(-0.000015259)
        );
        assert_eq!(Fixed(0x7fff_ffff), Fixed::from_f64(32768.0));
    }
}
<|endoftext|>


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

#[macro_use]
extern crate mozjs;
use mozjs::jsapi::JSTracer;
use mozjs::jsapi::JS_GC;
use mozjs::rust::Runtime;
use mozjs::rust::CustomTrace;
use mozjs::rust::CustomAutoRooter;

macro_rules! checked_trace_impl {
    ($flag:ident, $implementer:ident) => {
        static mut $flag: bool = false;
        unsafe impl CustomTrace for $implementer {
            fn trace(&self, _: *mut JSTracer) { unsafe { $flag = true; } }
        }
    };
}

/// Check if Rust reimplementation of CustomAutoRooter properly appends itself
/// to autoGCRooters stack list and if C++ inheritance was properly simulated
/// by checking if appropriate virtual trace function was called.
#[test]
fn virtual_trace_called() {
    pub struct TestStruct { }
    checked_trace_impl!(TRACE_FN_WAS_CALLED, TestStruct);

    let rt = Runtime::new().unwrap();
    let (rt, cx) = (rt.rt(), rt.cx());

    let mut rooter = CustomAutoRooter::new(TestStruct { });
    let _guard = rooter.root(cx);

    unsafe {
        JS_GC(rt);

        assert!(TRACE_FN_WAS_CALLED);
    }
}

#[test]
fn sequence_macro() {
    pub struct TestStruct { }
    checked_trace_impl!(TRACE_FN_WAS_CALLED, TestStruct);

    let rt = Runtime::new().unwrap();
    let (rt, cx) = (rt.rt(), rt.cx());

    rooted_seq!(in(cx) let _val = vec![TestStruct { }]);

    unsafe {
        JS_GC(rt);

        assert!(TRACE_FN_WAS_CALLED);
    }
}
<commit_msg>Use Cell in custom_auto_rooter tests<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#[macro_use]
extern crate mozjs;
use mozjs::jsapi::JSTracer;
use mozjs::jsapi::JS_GC;
use mozjs::rust::Runtime;
use mozjs::rust::CustomTrace;
use mozjs::rust::CustomAutoRooter;
use std::cell::Cell;

struct TraceCheck {
    trace_was_called: Cell<bool>
}

impl TraceCheck {
    fn new() -> TraceCheck {
        TraceCheck { trace_was_called: Cell::new(false) }
    }
}

unsafe impl CustomTrace for TraceCheck {
    fn trace(&self, _: *mut JSTracer) {
        self.trace_was_called.set(true);
    }
}

/// Check if Rust reimplementation of CustomAutoRooter properly appends itself
/// to autoGCRooters stack list and if C++ inheritance was properly simulated
/// by checking if appropriate virtual trace function was called.
#[test]
fn virtual_trace_called() {
    let rt = Runtime::new().unwrap();
    let (rt, cx) = (rt.rt(), rt.cx());

    let mut rooter = CustomAutoRooter::new(TraceCheck::new());
    let guard = rooter.root(cx);

    unsafe { JS_GC(rt); }

    assert!(guard.trace_was_called.get());
}

#[test]
fn sequence_macro() {
    let rt = Runtime::new().unwrap();
    let (rt, cx) = (rt.rt(), rt.cx());

    rooted_seq!(in(cx) let vec = vec![TraceCheck::new(), TraceCheck::new()]);

    unsafe { JS_GC(rt); }

    vec.iter().for_each(|elem| assert!(elem.trace_was_called.get()));
}
<|endoftext|>


<commit_before>use cocoa::base::{id, nil};

pub trait IntoOption: Sized {
    fn into_option(self) -> Option<Self>;
}

impl IntoOption for id {
    fn into_option(self) -> Option<Self> {
        match self != nil {
            true => Some(self),
            false => None,
        }
    }
}
<commit_msg>Remove dead code (unused as of d5391686a) (#1022)<commit_after><|endoftext|>


<commit_before>use mqtt::ffiasync;

use libc::{c_char, c_int, c_void};
use std::ffi::{CStr, CString};
use std::mem;
use std::ptr;
use std::slice;
use std::sync::Barrier;

pub enum PersistenceType {
    Default = 0,
    Nothing = 1,
    User    = 2,
}

#[derive(Debug)]
pub enum ConnectReturnCode {
    Success               = 0,
    UnacceptableProtocol  = 1,
    IdentifierRejected    = 2,
    ServerUnavailable     = 3,
    BadUsernameOrPassword = 4,
    NotAuthorized         = 5,
    Reserved              = 6,
}

#[derive(Debug)]
pub enum ConnectErr {
    ReturnCode(ConnectReturnCode),
    Callback
}

#[derive(Debug, Copy, Clone)]
pub enum MqttError {
    Code(i32),
    Bad
}

#[derive(Debug)]
pub enum Qos {
    FireAndForget  = 0,
    AtLeastOnce    = 1,
    OnceAndOneOnly = 2,
}

#[derive(Debug, Copy, Clone)]
pub enum ActionResult {
    None,
    Ok,
    Err(MqttError)
}

#[derive(Debug)]
pub struct Message {
    pub topic     : String,
    pub payload   : Vec<u8>,
    pub qos       : Qos,
    pub retained  : bool,
    pub duplicate : bool,
}

pub struct AsyncClient {
    handle        : ffiasync::MQTTAsync,
    barrier       : Barrier,
    action_result : ActionResult,
    messages      : Vec<Message>,
}

impl AsyncClient {

    /// Ensures the FFI struct is consistent for callback invocation.
    ///
    /// Because the user may move this struct, the `context` pointer
    /// passed back to FFI callbacks might be invalidated. This function
    /// should be called before FFI actions that might fire callbacks to ensure
    /// the self-pointer is valid.
    fn context(&mut self) -> *mut c_void {
        self as *mut _ as *mut c_void
    }

    pub fn new(address: &str, clientid: &str, persistence: PersistenceType) -> Result<AsyncClient, MqttError> {
        let mut handle                      = unsafe{mem::zeroed()};
        let mut persistence_context: c_void = unsafe{mem::zeroed()};

        let c_url          = CString::new(address).unwrap();
        let c_clientid     = CString::new(clientid).unwrap();
        let array_url      = c_url.as_bytes_with_nul();
        let array_clientid = c_clientid.as_bytes_with_nul();

        let mut error = unsafe {
            ffiasync::MQTTAsync_create(&mut handle,
                                       mem::transmute::<&u8, *const c_char>(&array_url[0]),
                                       mem::transmute::<&u8, *const c_char>(&array_clientid[0]),
                                       persistence as i32,
                                       &mut persistence_context)
        };

        match error {
            0   => { Ok( AsyncClient {
                        handle          : handle,
                        barrier         : Barrier::new(2),
                        action_result   : ActionResult::None,
                        messages        : Vec::new(),
                    })},
            err => Err(MqttError::Code(err))
        }
    }

    pub fn connect(&mut self, options: &mut AsyncConnectOptions) -> Result<(), ConnectErr> {
        info!("connect..");
        unsafe {
            ffiasync::MQTTAsync_setCallbacks(self.handle,
                                             self.context(),
                                             Some(Self::disconnected),
                                             Some(Self::received),
                                             None);
        }

        // fill in FFI private struct
        options.options.keepAliveInterval = options.keep_alive_interval;
        options.options.cleansession      = options.cleansession;
        options.options.maxInflight       = options.max_in_flight;
        options.options.connectTimeout    = options.connect_timeout;
        options.options.retryInterval     = options.retry_interval;

        // register callbacks
        options.options.context   = self.context();
        options.options.onSuccess = Some(Self::action_succeeded);
        options.options.onFailure = Some(Self::action_failed);

        self.action_result = ActionResult::None;
        let mut error = unsafe {
            ffiasync::MQTTAsync_connect(self.handle, &options.options)
        };
        if error == 0 {
            self.barrier.wait();
            if self.is_connected() {
                Ok(())
            } else {
                Err(ConnectErr::Callback)
            }
        } else {
            Err(ConnectErr::ReturnCode(
                match error {
                    1 => ConnectReturnCode::UnacceptableProtocol,
                    2 => ConnectReturnCode::IdentifierRejected,
                    3 => ConnectReturnCode::ServerUnavailable,
                    4 => ConnectReturnCode::BadUsernameOrPassword,
                    5 => ConnectReturnCode::NotAuthorized,
                    _ => ConnectReturnCode::Reserved,
            }))
        }
    }

    extern "C" fn disconnected(context: *mut c_void, cause: *mut c_char) -> () {
        warn!("disconnected");
        assert!(!context.is_null());
    }

    pub fn is_connected(&mut self) -> bool {
        let mut ret = unsafe {
            ffiasync::MQTTAsync_isConnected(self.handle)
        };

        match ret {
            1 => true,
            _ => false,
        }
    }

    pub fn send(&mut self, data: &[u8], topic: &str, qos: Qos) -> Result<(), MqttError> {
        info!("send..");
        let mut responseoption = ffiasync::MQTTAsync_responseOptions {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'R' as i8],
            struct_version  : 0,
            onSuccess       : Some(Self::action_succeeded),
            onFailure       : Some(Self::action_failed),
            context         : self.context(),
            token           : 0,
        };

        let mut message = ffiasync::MQTTAsync_message {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'M' as i8],
            struct_version  : 0,
            payloadlen      : data.len() as i32,
            payload         : unsafe {mem::transmute::<&u8, *mut c_void>(&data[0])},
            qos             : qos as c_int,
            retained        : 0,
            dup             : 0,
            msgid           : 0,
        };

        let c_topic        = CString::new(topic).unwrap();
        let array_topic    = c_topic.as_bytes_with_nul();
        self.action_result = ActionResult::None;

        let mut error = unsafe {
            ffiasync::MQTTAsync_sendMessage(self.handle,
                                            mem::transmute::<&u8, *const c_char>(&array_topic[0]),
                                            &mut message,
                                            &mut responseoption)
        };
        if error == 0 {
            self.barrier.wait();
            match self.action_result {
                ActionResult::None   => unreachable!(),
                ActionResult::Ok     => Ok(()),
                ActionResult::Err(x) => Err(x)
            }
        } else { Err(MqttError::Code(error)) }
    }

    pub fn subscribe(&mut self, topic: &str, qos: Qos) -> Result<(), MqttError> {
        info!("subscribe..");
        let mut responseoption = ffiasync::MQTTAsync_responseOptions {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'R' as i8],
            struct_version  : 0,
            onSuccess       : Some(Self::action_succeeded),
            onFailure       : Some(Self::action_failed),
            context         : self.context(),
            token           : 0,
        };

        let c_topic     = CString::new(topic).unwrap();
        let array_topic = c_topic.as_bytes_with_nul();

        let c_qos: i32 = match qos {
            Qos::FireAndForget  => 0,
            Qos::AtLeastOnce    => 1,
            Qos::OnceAndOneOnly => 2,
        };
        self.action_result = ActionResult::None;

        let mut error = unsafe {
            ffiasync::MQTTAsync_subscribe(self.handle,
                                          mem::transmute::<&u8, *const c_char>(&array_topic[0]),
                                          c_qos,
                                          &mut responseoption)
        };

        if error == 0 {
            self.barrier.wait();
            match self.action_result {
                ActionResult::None   => unreachable!(),
                ActionResult::Ok     => Ok(()),
                ActionResult::Err(x) => Err(x)
            }
        } else { Err(MqttError::Code(error)) }
    }

    extern "C" fn action_succeeded(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_successData) -> () {
        info!("success callback");
        assert!(!context.is_null());
        let selfclient: &mut AsyncClient = unsafe {mem::transmute(context)};
        selfclient.action_result = ActionResult::Ok;
        selfclient.barrier.wait();
    }

    extern "C" fn action_failed(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_failureData) -> () {
        info!("failure callback");
        assert!(!context.is_null());
        let selfclient : &mut AsyncClient = unsafe {mem::transmute(context)};
        if response.is_null() {
            selfclient.action_result = ActionResult::Err(MqttError::Bad);
        } else {
            let resp : &mut ffiasync::MQTTAsync_failureData = unsafe {mem::transmute(response)};
            selfclient.action_result = ActionResult::Err(MqttError::Code(resp.code));
        }
        selfclient.barrier.wait();
    }

    extern "C" fn received(context: *mut ::libc::c_void, topic_name: *mut ::libc::c_char, topic_len: ::libc::c_int, amessage: *mut ffiasync::MQTTAsync_message) -> i32 {
        let c_topic = unsafe {CStr::from_ptr(topic_name).to_bytes()};
        let topic   = String::from_utf8(c_topic.to_vec()).unwrap();
        assert_eq!(topic.len(), topic_len as usize);

        assert!(!amessage.is_null());
        let transmessage: &mut ffiasync::MQTTAsync_message = unsafe {mem::transmute(amessage)};
        let payload: &[u8] = unsafe {
                slice::from_raw_parts(transmessage.payload as *mut u8, transmessage.payloadlen as usize)
        };

        assert!(!context.is_null());
        let selfclient : &mut AsyncClient = unsafe {mem::transmute(context)};

        let qos = match transmessage.qos {
            0 => Qos::FireAndForget,
            1 => Qos::AtLeastOnce,
            2 => Qos::OnceAndOneOnly,
            _ => unreachable!(),
        };

        let retained: bool = match transmessage.retained {
            0 => false,
            1 => true,
            _ => unreachable!(),
        };

        let duplicate: bool = match transmessage.dup {
            0 => false,
            1 => true,
            _ => unreachable!(),
        };

        let msg = Message {
            topic     : topic,
            payload   : payload.to_vec(),
            qos       : qos,
            retained  : retained,
            duplicate : duplicate,
        };

        // TODO add mutex
        selfclient.messages.push(msg);

        let mut msg = amessage;
        unsafe{ffiasync::MQTTAsync_freeMessage(&mut msg)};
        unsafe{ffiasync::MQTTAsync_free(mem::transmute(topic_name))};
        1
    }

    pub fn messages(&mut self) -> AsyncClientIntoIterator {
        AsyncClientIntoIterator {
            client: self,
        }
    }
}

pub struct AsyncClientIntoIterator<'a> {
    client: &'a mut AsyncClient,
}

impl <'a>Iterator for AsyncClientIntoIterator<'a> {
    type Item = Message;
    fn next(&mut self) -> Option<Message> {
        // TODO add mutex
        self.client.messages.pop()
    }
}

impl Drop for AsyncClient {
    fn drop(&mut self) {
        unsafe{ffiasync::MQTTAsync_destroy(&mut self.handle)};
    }
}

pub struct AsyncConnectOptions {
    options: ffiasync::MQTTAsync_connectOptions,

    pub keep_alive_interval : i32,
    pub cleansession        : i32,
    pub max_in_flight       : i32,
    pub connect_timeout     : i32,
    pub retry_interval      : i32,
}
impl AsyncConnectOptions {
    pub fn new() -> AsyncConnectOptions {
        let ffioptions = ffiasync::MQTTAsync_connectOptions {
            struct_id           : ['M' as i8, 'Q' as i8, 'T' as i8, 'C' as i8],
            struct_version      : 3,
            keepAliveInterval   : 60,
            cleansession        : 1,
            maxInflight         : 10,
            will                : ptr::null_mut(),
            username            : ptr::null_mut(),
            password            : ptr::null_mut(),
            connectTimeout      : 30,
            retryInterval       : 0,
            ssl                 : ptr::null_mut(),
            onSuccess           : None,
            onFailure           : None,
            context             : ptr::null_mut(),
            serverURIcount      : 0,
            serverURIs          : ptr::null_mut(),
            MQTTVersion         : 0,
        };

        let options = AsyncConnectOptions {
            options             : ffioptions,

            keep_alive_interval : 20,
            cleansession        : 1,
            max_in_flight       : 10,
            connect_timeout     : 30,
            retry_interval      : 0,
        };

        options
    }
}

pub struct AsyncDisconnectOptions {
    options: ffiasync::MQTTAsync_disconnectOptions,
}
impl AsyncDisconnectOptions {

    pub fn new() -> ffiasync::MQTTAsync_disconnectOptions {
        let options = ffiasync::MQTTAsync_disconnectOptions {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'D' as i8],
            struct_version  : 0,
            timeout         : 0,
            onSuccess       : ptr::null_mut(),
            onFailure       : ptr::null_mut(),
            context         : ptr::null_mut(),
        };

        options
    }
}

pub struct AsyncMessage {
    options: ffiasync::MQTTAsync_message,
}
impl AsyncMessage {

    pub fn new() -> ffiasync::MQTTAsync_message {
        let message = ffiasync::MQTTAsync_message {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'M' as i8],
            struct_version  : 0,
            payloadlen      : 0,
            payload         : ptr::null_mut(),
            qos             : 0,
            retained        : 0,
            dup             : 0,
            msgid           : 0,
        };

        message
    }
}
<commit_msg>add mutex to AsyncClient receive callback<commit_after>use mqtt::ffiasync;

use libc::{c_char, c_int, c_void};
use std::ffi::{CStr, CString};
use std::mem;
use std::ptr;
use std::slice;
use std::sync::{Barrier, Mutex};

pub enum PersistenceType {
    Default = 0,
    Nothing = 1,
    User    = 2,
}

#[derive(Debug)]
pub enum ConnectReturnCode {
    Success               = 0,
    UnacceptableProtocol  = 1,
    IdentifierRejected    = 2,
    ServerUnavailable     = 3,
    BadUsernameOrPassword = 4,
    NotAuthorized         = 5,
    Reserved              = 6,
}

#[derive(Debug)]
pub enum ConnectErr {
    ReturnCode(ConnectReturnCode),
    Callback
}

#[derive(Debug, Copy, Clone)]
pub enum MqttError {
    Code(i32),
    Bad
}

#[derive(Debug)]
pub enum Qos {
    FireAndForget  = 0,
    AtLeastOnce    = 1,
    OnceAndOneOnly = 2,
}

#[derive(Debug, Copy, Clone)]
pub enum ActionResult {
    None,
    Ok,
    Err(MqttError)
}

#[derive(Debug)]
pub struct Message {
    pub topic     : String,
    pub payload   : Vec<u8>,
    pub qos       : Qos,
    pub retained  : bool,
    pub duplicate : bool,
}

pub struct AsyncClient {
    handle        : ffiasync::MQTTAsync,
    barrier       : Barrier,
    action_result : ActionResult,
    messages      : Mutex<Vec<Message>>,
}

impl AsyncClient {

    /// Ensures the FFI struct is consistent for callback invocation.
    ///
    /// Because the user may move this struct, the `context` pointer
    /// passed back to FFI callbacks might be invalidated. This function
    /// should be called before FFI actions that might fire callbacks to ensure
    /// the self-pointer is valid.
    fn context(&mut self) -> *mut c_void {
        self as *mut _ as *mut c_void
    }

    pub fn new(address: &str, clientid: &str, persistence: PersistenceType) -> Result<AsyncClient, MqttError> {
        let mut handle                      = unsafe{mem::zeroed()};
        let mut persistence_context: c_void = unsafe{mem::zeroed()};

        let c_url          = CString::new(address).unwrap();
        let c_clientid     = CString::new(clientid).unwrap();
        let array_url      = c_url.as_bytes_with_nul();
        let array_clientid = c_clientid.as_bytes_with_nul();

        let mut error = unsafe {
            ffiasync::MQTTAsync_create(&mut handle,
                                       mem::transmute::<&u8, *const c_char>(&array_url[0]),
                                       mem::transmute::<&u8, *const c_char>(&array_clientid[0]),
                                       persistence as i32,
                                       &mut persistence_context)
        };

        match error {
            0   => { Ok( AsyncClient {
                        handle          : handle,
                        barrier         : Barrier::new(2),
                        action_result   : ActionResult::None,
                        messages        : Mutex::new(Vec::new()),
                    })},
            err => Err(MqttError::Code(err))
        }
    }

    pub fn connect(&mut self, options: &mut AsyncConnectOptions) -> Result<(), ConnectErr> {
        info!("connect..");
        unsafe {
            ffiasync::MQTTAsync_setCallbacks(self.handle,
                                             self.context(),
                                             Some(Self::disconnected),
                                             Some(Self::received),
                                             None);
        }

        // fill in FFI private struct
        options.options.keepAliveInterval = options.keep_alive_interval;
        options.options.cleansession      = options.cleansession;
        options.options.maxInflight       = options.max_in_flight;
        options.options.connectTimeout    = options.connect_timeout;
        options.options.retryInterval     = options.retry_interval;

        // register callbacks
        options.options.context   = self.context();
        options.options.onSuccess = Some(Self::action_succeeded);
        options.options.onFailure = Some(Self::action_failed);

        self.action_result = ActionResult::None;
        let mut error = unsafe {
            ffiasync::MQTTAsync_connect(self.handle, &options.options)
        };
        if error == 0 {
            self.barrier.wait();
            if self.is_connected() {
                Ok(())
            } else {
                Err(ConnectErr::Callback)
            }
        } else {
            Err(ConnectErr::ReturnCode(
                match error {
                    1 => ConnectReturnCode::UnacceptableProtocol,
                    2 => ConnectReturnCode::IdentifierRejected,
                    3 => ConnectReturnCode::ServerUnavailable,
                    4 => ConnectReturnCode::BadUsernameOrPassword,
                    5 => ConnectReturnCode::NotAuthorized,
                    _ => ConnectReturnCode::Reserved,
            }))
        }
    }

    extern "C" fn disconnected(context: *mut c_void, cause: *mut c_char) -> () {
        warn!("disconnected");
        assert!(!context.is_null());
    }

    pub fn is_connected(&mut self) -> bool {
        let mut ret = unsafe {
            ffiasync::MQTTAsync_isConnected(self.handle)
        };

        match ret {
            1 => true,
            _ => false,
        }
    }

    pub fn send(&mut self, data: &[u8], topic: &str, qos: Qos) -> Result<(), MqttError> {
        info!("send..");
        let mut responseoption = ffiasync::MQTTAsync_responseOptions {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'R' as i8],
            struct_version  : 0,
            onSuccess       : Some(Self::action_succeeded),
            onFailure       : Some(Self::action_failed),
            context         : self.context(),
            token           : 0,
        };

        let mut message = ffiasync::MQTTAsync_message {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'M' as i8],
            struct_version  : 0,
            payloadlen      : data.len() as i32,
            payload         : unsafe {mem::transmute::<&u8, *mut c_void>(&data[0])},
            qos             : qos as c_int,
            retained        : 0,
            dup             : 0,
            msgid           : 0,
        };

        let c_topic        = CString::new(topic).unwrap();
        let array_topic    = c_topic.as_bytes_with_nul();
        self.action_result = ActionResult::None;

        let mut error = unsafe {
            ffiasync::MQTTAsync_sendMessage(self.handle,
                                            mem::transmute::<&u8, *const c_char>(&array_topic[0]),
                                            &mut message,
                                            &mut responseoption)
        };
        if error == 0 {
            self.barrier.wait();
            match self.action_result {
                ActionResult::None   => unreachable!(),
                ActionResult::Ok     => Ok(()),
                ActionResult::Err(x) => Err(x)
            }
        } else { Err(MqttError::Code(error)) }
    }

    pub fn subscribe(&mut self, topic: &str, qos: Qos) -> Result<(), MqttError> {
        info!("subscribe..");
        let mut responseoption = ffiasync::MQTTAsync_responseOptions {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'R' as i8],
            struct_version  : 0,
            onSuccess       : Some(Self::action_succeeded),
            onFailure       : Some(Self::action_failed),
            context         : self.context(),
            token           : 0,
        };

        let c_topic     = CString::new(topic).unwrap();
        let array_topic = c_topic.as_bytes_with_nul();

        let c_qos: i32 = match qos {
            Qos::FireAndForget  => 0,
            Qos::AtLeastOnce    => 1,
            Qos::OnceAndOneOnly => 2,
        };
        self.action_result = ActionResult::None;

        let mut error = unsafe {
            ffiasync::MQTTAsync_subscribe(self.handle,
                                          mem::transmute::<&u8, *const c_char>(&array_topic[0]),
                                          c_qos,
                                          &mut responseoption)
        };

        if error == 0 {
            self.barrier.wait();
            match self.action_result {
                ActionResult::None   => unreachable!(),
                ActionResult::Ok     => Ok(()),
                ActionResult::Err(x) => Err(x)
            }
        } else { Err(MqttError::Code(error)) }
    }

    extern "C" fn action_succeeded(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_successData) -> () {
        info!("success callback");
        assert!(!context.is_null());
        let selfclient: &mut AsyncClient = unsafe {mem::transmute(context)};
        selfclient.action_result = ActionResult::Ok;
        selfclient.barrier.wait();
    }

    extern "C" fn action_failed(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_failureData) -> () {
        info!("failure callback");
        assert!(!context.is_null());
        let selfclient : &mut AsyncClient = unsafe {mem::transmute(context)};
        if response.is_null() {
            selfclient.action_result = ActionResult::Err(MqttError::Bad);
        } else {
            let resp : &mut ffiasync::MQTTAsync_failureData = unsafe {mem::transmute(response)};
            selfclient.action_result = ActionResult::Err(MqttError::Code(resp.code));
        }
        selfclient.barrier.wait();
    }

    extern "C" fn received(context: *mut ::libc::c_void, topic_name: *mut ::libc::c_char, topic_len: ::libc::c_int, amessage: *mut ffiasync::MQTTAsync_message) -> i32 {
        let c_topic = unsafe {CStr::from_ptr(topic_name).to_bytes()};
        let topic   = String::from_utf8(c_topic.to_vec()).unwrap();
        assert_eq!(topic.len(), topic_len as usize);

        assert!(!amessage.is_null());
        let transmessage: &mut ffiasync::MQTTAsync_message = unsafe {mem::transmute(amessage)};
        let payload: &[u8] = unsafe {
                slice::from_raw_parts(transmessage.payload as *mut u8, transmessage.payloadlen as usize)
        };

        assert!(!context.is_null());
        let selfclient : &mut AsyncClient = unsafe {mem::transmute(context)};

        let qos = match transmessage.qos {
            0 => Qos::FireAndForget,
            1 => Qos::AtLeastOnce,
            2 => Qos::OnceAndOneOnly,
            _ => unreachable!(),
        };

        let retained: bool = match transmessage.retained {
            0 => false,
            1 => true,
            _ => unreachable!(),
        };

        let duplicate: bool = match transmessage.dup {
            0 => false,
            1 => true,
            _ => unreachable!(),
        };

        let msg = Message {
            topic     : topic,
            payload   : payload.to_vec(),
            qos       : qos,
            retained  : retained,
            duplicate : duplicate,
        };

        let mut messages = selfclient.messages.lock().unwrap();
        messages.push(msg);

        let mut msg = amessage;
        unsafe{ffiasync::MQTTAsync_freeMessage(&mut msg)};
        unsafe{ffiasync::MQTTAsync_free(mem::transmute(topic_name))};
        1
    }

    pub fn messages(&mut self) -> AsyncClientIntoIterator {
        AsyncClientIntoIterator {
            client: self,
        }
    }
}

pub struct AsyncClientIntoIterator<'a> {
    client: &'a mut AsyncClient,
}

impl <'a>Iterator for AsyncClientIntoIterator<'a> {
    type Item = Message;
    fn next(&mut self) -> Option<Message> {
        let mut messages = self.client.messages.lock().unwrap();
        if messages.len() > 0 {
            Some(messages.remove(0))
        }
        else {
            None
        }
    }
}

impl Drop for AsyncClient {
    fn drop(&mut self) {
        unsafe{ffiasync::MQTTAsync_destroy(&mut self.handle)};
    }
}

pub struct AsyncConnectOptions {
    options: ffiasync::MQTTAsync_connectOptions,

    pub keep_alive_interval : i32,
    pub cleansession        : i32,
    pub max_in_flight       : i32,
    pub connect_timeout     : i32,
    pub retry_interval      : i32,
}
impl AsyncConnectOptions {
    pub fn new() -> AsyncConnectOptions {
        let ffioptions = ffiasync::MQTTAsync_connectOptions {
            struct_id           : ['M' as i8, 'Q' as i8, 'T' as i8, 'C' as i8],
            struct_version      : 3,
            keepAliveInterval   : 60,
            cleansession        : 1,
            maxInflight         : 10,
            will                : ptr::null_mut(),
            username            : ptr::null_mut(),
            password            : ptr::null_mut(),
            connectTimeout      : 30,
            retryInterval       : 0,
            ssl                 : ptr::null_mut(),
            onSuccess           : None,
            onFailure           : None,
            context             : ptr::null_mut(),
            serverURIcount      : 0,
            serverURIs          : ptr::null_mut(),
            MQTTVersion         : 0,
        };

        let options = AsyncConnectOptions {
            options             : ffioptions,

            keep_alive_interval : 20,
            cleansession        : 1,
            max_in_flight       : 10,
            connect_timeout     : 30,
            retry_interval      : 0,
        };

        options
    }
}

pub struct AsyncDisconnectOptions {
    options: ffiasync::MQTTAsync_disconnectOptions,
}
impl AsyncDisconnectOptions {

    pub fn new() -> ffiasync::MQTTAsync_disconnectOptions {
        let options = ffiasync::MQTTAsync_disconnectOptions {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'D' as i8],
            struct_version  : 0,
            timeout         : 0,
            onSuccess       : ptr::null_mut(),
            onFailure       : ptr::null_mut(),
            context         : ptr::null_mut(),
        };

        options
    }
}

pub struct AsyncMessage {
    options: ffiasync::MQTTAsync_message,
}
impl AsyncMessage {

    pub fn new() -> ffiasync::MQTTAsync_message {
        let message = ffiasync::MQTTAsync_message {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'M' as i8],
            struct_version  : 0,
            payloadlen      : 0,
            payload         : ptr::null_mut(),
            qos             : 0,
            retained        : 0,
            dup             : 0,
            msgid           : 0,
        };

        message
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::convert::Into;

use data::packet::Packet;
use data::frame::ArcFrame;
use data::value::Value;

use error::*;

pub trait Encoder : Send {
    fn get_extradata(&self) -> Option<Vec<u8>>;
    fn send_frame(&mut self, pkt: &ArcFrame) -> Result<()>;
    fn receive_packet(&mut self) -> Result<Packet>;
    fn flush(&mut self) -> Result<()>;

    fn configure(&mut self) -> Result<()>;
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
    // fn get_option(&mut self, key: &str) -> Option<Value>;
}

pub struct Context {
    enc: Box<Encoder>,
    // TODO: Queue up packets/frames
    // TODO: Store here more information
    // TODO: Have a resource pool
    // format: Format
}

impl Context {
    // TODO: More constructors
    pub fn by_name(codecs: &Codecs, name: &str) -> Option<Context> {
        if let Some(builder) = codecs.by_name(name) {
            let enc = builder.create();
            Some(Context { enc: enc })
        } else {
            None
        }
    }

    pub fn configure(&mut self) -> Result<()> {
        self.enc.configure()
    }

    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
        where V: Into<Value<'a>>
    {
        // TODO: support more options
        self.enc.set_option(key, val.into())
    }

    pub fn get_extradata(&mut self) -> Option<Vec<u8>> {
        self.enc.get_extradata()
    }
    pub fn send_frame(&mut self, frame: &ArcFrame) -> Result<()> {
        self.enc.send_frame(frame)
    }
    // TODO: Return an Event?
    pub fn receive_packet(&mut self) -> Result<Packet> {
        self.enc.receive_packet()
    }

    pub fn flush(&mut self) -> Result<()> {
        self.enc.flush()
    }
}

#[derive(Debug)]
pub struct Descr {
    pub codec: &'static str,
    pub name: &'static str,
    pub desc: &'static str,
    pub mime: &'static str,
    // TODO more fields regarding capabilities
}

pub trait Descriptor {
    fn create(&self) -> Box<Encoder>;
    fn describe<'a>(&'a self) -> &'a Descr;
}

pub struct Codecs {
    list: HashMap<&'static str, Vec<&'static Descriptor>>
}

pub use common::CodecList;

impl CodecList for Codecs {
    type D = Descriptor;
    fn new() -> Codecs {
        Codecs { list: HashMap::new() }
    }
    // TODO more lookup functions
    fn by_name(&self, name: &str) -> Option<&'static Descriptor> {
        if let Some(descs) = self.list.get(name) {
            Some(descs[0])
        } else {
            None
        }
    }

    fn append(&mut self, desc: &'static Descriptor) {
        let codec_name = desc.describe().codec;

        self.list.entry(codec_name).or_insert(Vec::new()).push(desc);
    }
}

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

    mod dummy {
        use super::super::*;
        use std::rc::Rc;
        use data::pixel::Formaton;
        use super::super::super::error::ErrorKind;

        struct Enc {
            state: usize,
            w: Option<usize>,
            h: Option<usize>,
            format: Option<Rc<Formaton>>
        }

        pub struct Des {
            descr: Descr,
        }

        impl Descriptor for Des {
            fn create(&self) -> Box<Encoder> {
                box Enc { state: 0, w: None, h: None, format: None }
            }
            fn describe<'a>(&'a self) -> &'a Descr {
                &self.descr
            }
        }

        impl Encoder for Enc {
            fn configure(&mut self) -> Result<()> {
                if self.h.is_some() && self.w.is_some() && self.format.is_some() {
                    Ok(())
                } else {
                    Err(ErrorKind::ConfigurationIncomplete.into())
                }
            }
            fn get_extradata(&self) -> Option<Vec<u8>> {
                Some(vec![self.state as u8; 1])
            }
            fn send_frame(&mut self, _frame: &ArcFrame) -> Result<()> {
                self.state += 1;
                Ok(())
            }
            fn receive_packet(&mut self) -> Result<Packet> {
                let mut p = Packet::with_capacity(1);

                p.data.push(self.state as u8);

                Ok(p)
            }
            fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()> {
                match (key, val) {
                    ("w", Value::U64(v)) => self.w = Some(v as usize),
                    ("h", Value::U64(v)) => self.h = Some(v as usize),
                    ("format", Value::Formaton(f)) => self.format = Some(f),
                    _ => return Err(ErrorKind::Unsupported.into())
                }

                Ok(())
            }
            fn flush(&mut self) -> Result<()> {
                Ok(())
            }
        }

        pub const DUMMY_DESCR: &Des = &Des {
            descr: Descr {
                codec: "dummy",
                name: "dummy",
                desc: "Dummy encoder",
                mime: "x-application/dummy",
            }
        };
    }
    use self::dummy::DUMMY_DESCR;

    #[test]
    fn lookup() {
        let codecs = Codecs::from_list(&[DUMMY_DESCR]);

        let _enc = codecs.by_name("dummy");
    }
}
<commit_msg>codec: Unbreak encoder test<commit_after>use std::collections::HashMap;
use std::convert::Into;

use data::packet::Packet;
use data::frame::ArcFrame;
use data::value::Value;

use error::*;

pub trait Encoder : Send {
    fn get_extradata(&self) -> Option<Vec<u8>>;
    fn send_frame(&mut self, pkt: &ArcFrame) -> Result<()>;
    fn receive_packet(&mut self) -> Result<Packet>;
    fn flush(&mut self) -> Result<()>;

    fn configure(&mut self) -> Result<()>;
    fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()>;
    // fn get_option(&mut self, key: &str) -> Option<Value>;
}

pub struct Context {
    enc: Box<Encoder>,
    // TODO: Queue up packets/frames
    // TODO: Store here more information
    // TODO: Have a resource pool
    // format: Format
}

impl Context {
    // TODO: More constructors
    pub fn by_name(codecs: &Codecs, name: &str) -> Option<Context> {
        if let Some(builder) = codecs.by_name(name) {
            let enc = builder.create();
            Some(Context { enc: enc })
        } else {
            None
        }
    }

    pub fn configure(&mut self) -> Result<()> {
        self.enc.configure()
    }

    pub fn set_option<'a, V>(&mut self, key: &str, val: V) -> Result<()>
        where V: Into<Value<'a>>
    {
        // TODO: support more options
        self.enc.set_option(key, val.into())
    }

    pub fn get_extradata(&mut self) -> Option<Vec<u8>> {
        self.enc.get_extradata()
    }
    pub fn send_frame(&mut self, frame: &ArcFrame) -> Result<()> {
        self.enc.send_frame(frame)
    }
    // TODO: Return an Event?
    pub fn receive_packet(&mut self) -> Result<Packet> {
        self.enc.receive_packet()
    }

    pub fn flush(&mut self) -> Result<()> {
        self.enc.flush()
    }
}

#[derive(Debug)]
pub struct Descr {
    pub codec: &'static str,
    pub name: &'static str,
    pub desc: &'static str,
    pub mime: &'static str,
    // TODO more fields regarding capabilities
}

pub trait Descriptor {
    fn create(&self) -> Box<Encoder>;
    fn describe<'a>(&'a self) -> &'a Descr;
}

pub struct Codecs {
    list: HashMap<&'static str, Vec<&'static Descriptor>>
}

pub use common::CodecList;

impl CodecList for Codecs {
    type D = Descriptor;
    fn new() -> Codecs {
        Codecs { list: HashMap::new() }
    }
    // TODO more lookup functions
    fn by_name(&self, name: &str) -> Option<&'static Descriptor> {
        if let Some(descs) = self.list.get(name) {
            Some(descs[0])
        } else {
            None
        }
    }

    fn append(&mut self, desc: &'static Descriptor) {
        let codec_name = desc.describe().codec;

        self.list.entry(codec_name).or_insert(Vec::new()).push(desc);
    }
}

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

    mod dummy {
        use super::super::*;
        use std::sync::Arc;
        use data::pixel::Formaton;
        use super::super::super::error::ErrorKind;

        struct Enc {
            state: usize,
            w: Option<usize>,
            h: Option<usize>,
            format: Option<Arc<Formaton>>
        }

        pub struct Des {
            descr: Descr,
        }

        impl Descriptor for Des {
            fn create(&self) -> Box<Encoder> {
                box Enc { state: 0, w: None, h: None, format: None }
            }
            fn describe<'a>(&'a self) -> &'a Descr {
                &self.descr
            }
        }

        impl Encoder for Enc {
            fn configure(&mut self) -> Result<()> {
                if self.h.is_some() && self.w.is_some() && self.format.is_some() {
                    Ok(())
                } else {
                    Err(ErrorKind::ConfigurationIncomplete.into())
                }
            }
            fn get_extradata(&self) -> Option<Vec<u8>> {
                Some(vec![self.state as u8; 1])
            }
            fn send_frame(&mut self, _frame: &ArcFrame) -> Result<()> {
                self.state += 1;
                Ok(())
            }
            fn receive_packet(&mut self) -> Result<Packet> {
                let mut p = Packet::with_capacity(1);

                p.data.push(self.state as u8);

                Ok(p)
            }
            fn set_option<'a>(&mut self, key: &str, val: Value<'a>) -> Result<()> {
                match (key, val) {
                    ("w", Value::U64(v)) => self.w = Some(v as usize),
                    ("h", Value::U64(v)) => self.h = Some(v as usize),
                    ("format", Value::Formaton(f)) => self.format = Some(f),
                    _ => return Err(ErrorKind::Unsupported.into())
                }

                Ok(())
            }
            fn flush(&mut self) -> Result<()> {
                Ok(())
            }
        }

        pub const DUMMY_DESCR: &Des = &Des {
            descr: Descr {
                codec: "dummy",
                name: "dummy",
                desc: "Dummy encoder",
                mime: "x-application/dummy",
            }
        };
    }
    use self::dummy::DUMMY_DESCR;

    #[test]
    fn lookup() {
        let codecs = Codecs::from_list(&[DUMMY_DESCR]);

        let _enc = codecs.by_name("dummy");
    }
}
<|endoftext|>