jaded/
convert.rs

1//! Traits and methods used to convert deserialized Java objects into useful
2//! structures.
3use crate::{ConversionError, ConversionResult, PrimitiveType, Value};
4
5/// Trait for structs that can be converted from a deserialized Java Value
6pub trait FromJava: Sized {
7    /// Convert content read from a java stream into Self
8    fn from_value(value: &Value) -> ConversionResult<Self>;
9}
10
11impl<T: FromJava> FromJava for Option<T> {
12    fn from_value(value: &Value) -> ConversionResult<Self> {
13        match value {
14            Value::Null => Ok(None),
15            _ => Ok(Some(T::from_value(value)?)),
16        }
17    }
18}
19
20impl FromJava for String {
21    fn from_value(value: &Value) -> ConversionResult<Self> {
22        match value {
23            Value::JavaString(s) => Ok(s.to_string()),
24            Value::Null => Err(ConversionError::NullPointerException),
25            _ => Err(ConversionError::InvalidType("string")),
26        }
27    }
28}
29
30/// Implement FromJava for a primitive type. In Java a primitive can be a
31/// 'real' primitive (int, double etc), or a boxed Object version
32/// (java.lang.Integer, java.lang.Double) etc. This lets both variants be
33/// converted to the equivalent rust types (i32, f64 etc).
34macro_rules! from_value_for_primitive {
35    // Optionally take a string literal as boxed object names don't always match
36    // primitive name, eg int -> Integer
37    ($type:ty, $primitive:ident) => {
38        from_value_for_primitive! {$type, $primitive, stringify!($primitive)}
39    };
40    // Convert either a primitive or boxed primitive into its rust equivalent
41    ($type:ty, $primitive:ident, $java_name:expr) => {
42        impl FromJava for $type {
43            fn from_value(value: &Value) -> ConversionResult<Self> {
44                match value {
45                    Value::Object(data) => {
46                        let java_class_name = concat!("java.lang.", $java_name);
47                        if data.class_name() == java_class_name {
48                            match data.get_field("value") {
49                                Some(Value::Primitive(PrimitiveType::$primitive(v))) => Ok(*v),
50                                Some(_) => Err(ConversionError::InvalidType(stringify!($type))),
51                                None => Err(ConversionError::FieldNotFound("value".to_string())),
52                            }
53                        } else {
54                            Err(ConversionError::InvalidType(java_class_name))
55                        }
56                    }
57                    Value::Primitive(PrimitiveType::$primitive(i)) => Ok(*i),
58                    _ => Err(ConversionError::InvalidType($java_name)),
59                }
60            }
61        }
62    };
63}
64
65from_value_for_primitive!(u8, Byte);
66from_value_for_primitive!(i16, Short);
67from_value_for_primitive!(i32, Int, "Integer");
68from_value_for_primitive!(i64, Long);
69from_value_for_primitive!(f32, Float);
70from_value_for_primitive!(f64, Double);
71from_value_for_primitive!(char, Char, "Character");
72from_value_for_primitive!(bool, Boolean);
73
74impl<T: FromJava> FromJava for Box<T> {
75    fn from_value(value: &Value) -> ConversionResult<Self> {
76        Ok(Box::new(T::from_value(value)?))
77    }
78}
79
80impl<T: FromJava> FromJava for Vec<T> {
81    fn from_value(value: &Value) -> ConversionResult<Self> {
82        match value {
83            Value::Array(items) => Ok(items
84                .iter()
85                .map(T::from_value)
86                .collect::<ConversionResult<Vec<_>>>()?),
87            Value::PrimitiveArray(items) => Ok(items
88                .iter()
89                .map(|p| T::from_value(&Value::Primitive(*p)))
90                .collect::<ConversionResult<Vec<_>>>()?),
91            _ => Err(ConversionError::InvalidType("array")),
92        }
93    }
94}