1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
use ::once_cell::sync::Lazy;
use ::std::collections::HashMap;
use ::syn::*;
use crate::helpers::*;

/// Builtin scalar behaviors: `f32`, `u32`, ...
///
/// The behavior for different scalars is shared into this object. Handled here are:
///
///  - `char`
///  - `f32`
///  - `f64`
///  - `u8`
///  - `u16`
///  - `u32`
///  - `u64`
///  - `usize`
///  - `i8`
///  - `i16`
///  - `i32`
///  - `i64`
///  - `isize`
pub struct Behavior;

static NATIVE_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
    let mut m = HashMap::new();
    m.insert("char", "int");
    m.insert("f32", "double");
    m.insert("f64", "double");
    m.insert("u8", "int");
    m.insert("u16", "int");
    m.insert("u32", "int");
    m.insert("u64", "int");
    //m.insert("usize", "int"); TODO un-handled usize/isize scalar types
    m.insert("i8", "int");
    m.insert("i16", "int");
    m.insert("i32", "int");
    m.insert("i64", "int");
    //m.insert("isize", "int"); TODO un-handled usize/isize scalar types
    m
});

#[allow(dead_code)]
static SHIM_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
    let mut m = HashMap::new();
    m.insert("char", "Uint32");
    m.insert("f32", "Float");
    m.insert("f64", "Double");
    m.insert("u8", "Uint8");
    m.insert("u16", "Uint16");
    m.insert("u32", "Uint32");
    m.insert("u64", "Uint64");
    //m.insert("usize", "int"); TODO un-handled usize/isize scalar types
    m.insert("i8", "Int8");
    m.insert("i16", "Int16");
    m.insert("i32", "Int32");
    m.insert("i64", "Int64");
    //m.insert("isize", "int"); TODO un-handled usize/isize scalar types
    m
});

impl super::Behavior for Behavior {
    fn is(&self, sty: &Type) -> bool {
        if let Type::Path(tp) = sty {
            NATIVE_TYPES.keys().any(|t| {
                parse_str::<Path>(t).unwrap() == tp.path
            })
        } else {
            false
        }
    }
    fn imports(&self, _sty: &Type, _pkg: &str, _crate_name: &str) -> Vec<String> {
        vec!["dart:ffi".to_owned()]
    }
    fn name(&self, sty: &Type) -> String { type_name_from_path(sty) }

    fn shim(&self, sty: &Type) -> String {
        if let Type::Path(tp) = sty {
            let name = tp.path.get_ident().expect(".shim() with non-scalar type").to_string();
            SHIM_TYPES.get(name.as_str()).expect(".shim() with non-scalar type").to_string()
        } else {
            panic!("cannot call scalar .ffi() with non-scalar type");
        }
    }

    fn ffi(&self, sty: &Type) -> String {
        self.native(sty)
    }

    fn native(&self, sty: &Type) -> String {
        if let Type::Path(tp) = sty {
            let name = tp.path.get_ident().expect(".native() with non-scalar type").to_string();
            NATIVE_TYPES.get(name.as_str()).expect(".native() with non-scalar type").to_string()
        } else {
            panic!("cannot call scalar .native() with non-scalar type");
        }
    }

    fn native_to_ffi(&self, _sty: &Type, expr: String) -> String {
        expr
    }

    fn ffi_to_native(&self, _sty: &Type, expr: String) -> String {
        expr
    }

}