| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use serde::de::{Deserialize as DeserializeIface, Deserializer}; |
| use serde_derive::Deserialize; |
| use std::collections::HashMap; |
| |
| use std::sync::{Arc, Weak}; |
| |
| use crate::error::{Error, Result}; |
| use crate::value::Value; |
| |
| /// Trait for deserialized structs that have a `name` field. Basically gives us a structural type |
| /// for "Has a String field named 'name'." |
| trait Named { |
| fn name(&self) -> String; |
| } |
| |
| impl<T: Named> Named for Arc<T> { |
| fn name(&self) -> String { |
| Arc::as_ref(self).name() |
| } |
| } |
| |
| macro_rules! named { |
| ($ident:ty) => { |
| impl Named for $ident { |
| fn name(&self) -> String { |
| self.name.clone() |
| } |
| } |
| }; |
| } |
| |
| /// Deserializer helper for fidl::ObjectType |
| fn object_type<'de, D: Deserializer<'de>>( |
| deserializer: D, |
| ) -> std::result::Result<Option<fidl::ObjectType>, D::Error> { |
| Ok(Option::<u32>::deserialize(deserializer)?.map(|x| fidl::ObjectType::from_raw(x))) |
| } |
| |
| /// Deserializer helper for composed protocols |
| fn composed_protocols<'de, D: Deserializer<'de>>( |
| deserializer: D, |
| ) -> std::result::Result<Vec<String>, D::Error> { |
| #[derive(Deserialize)] |
| struct ComposedProtocol { |
| name: String, |
| } |
| Ok(Vec::<ComposedProtocol>::deserialize(deserializer)?.into_iter().map(|x| x.name).collect()) |
| } |
| |
| /// Deserializer helper for fidl::ObjectType |
| fn rights<'de, D: Deserializer<'de>>( |
| deserializer: D, |
| ) -> std::result::Result<Option<fidl::Rights>, D::Error> { |
| if let Some(rights) = Option::<u32>::deserialize(deserializer)? { |
| Ok(Some(fidl::Rights::from_bits_truncate(rights))) |
| } else { |
| Ok(None) |
| } |
| } |
| |
| /// Deserializer helper that gets a list of values, but then packs them into a hashmap by name. |
| fn hash_by_name<'de, D: Deserializer<'de>, T: Named + DeserializeIface<'de>>( |
| deserializer: D, |
| ) -> std::result::Result<HashMap<String, T>, D::Error> { |
| let mut ret = HashMap::new(); |
| for item in Vec::<T>::deserialize(deserializer)? { |
| ret.insert(item.name().clone(), item); |
| } |
| Ok(ret) |
| } |
| |
| /// Same as `hash_by_name` but wraps the inserted values in an Arc. |
| fn hash_by_name_arc<'de, D: Deserializer<'de>, T: Named + DeserializeIface<'de>>( |
| deserializer: D, |
| ) -> std::result::Result<HashMap<String, Arc<T>>, D::Error> { |
| let mut ret = HashMap::new(); |
| for item in Vec::<T>::deserialize(deserializer)? { |
| ret.insert(item.name().clone(), Arc::new(item)); |
| } |
| Ok(ret) |
| } |
| |
| /// Deserializer helper that gets a list of TableOrUnionMembers, but then packs them into a |
| /// hashmap by ordinal. |
| fn hash_by_ordinal<'de, D: Deserializer<'de>>( |
| deserializer: D, |
| ) -> std::result::Result<HashMap<u64, TableOrUnionMember>, D::Error> { |
| let mut ret = HashMap::new(); |
| for item in Vec::<TableOrUnionMember>::deserialize(deserializer)? { |
| ret.insert(item.ordinal, item); |
| } |
| Ok(ret) |
| } |
| |
| /// Gets the size for a struct declaration by stripping away a field shape object. |
| fn extract_struct_size<'de, D: Deserializer<'de>>( |
| deserializer: D, |
| ) -> std::result::Result<usize, D::Error> { |
| Ok(TypeShape::deserialize(deserializer)?.inline_size) |
| } |
| |
| /// Gets the offset for a struct member by stripping away a field shape object. |
| fn extract_member_offset<'de, D: Deserializer<'de>>( |
| deserializer: D, |
| ) -> std::result::Result<usize, D::Error> { |
| Ok(MemberShape::deserialize(deserializer)?.offset) |
| } |
| |
| #[derive(Deserialize)] |
| struct Module { |
| name: String, |
| #[serde(deserialize_with = "hash_by_name")] |
| bits_declarations: HashMap<String, Bits>, |
| #[serde(deserialize_with = "hash_by_name")] |
| enum_declarations: HashMap<String, Enum>, |
| #[serde(deserialize_with = "hash_by_name")] |
| protocol_declarations: HashMap<String, Protocol>, |
| #[serde(deserialize_with = "hash_by_name")] |
| table_declarations: HashMap<String, TableOrUnion>, |
| #[serde(deserialize_with = "hash_by_name")] |
| struct_declarations: HashMap<String, Struct>, |
| #[serde(deserialize_with = "hash_by_name")] |
| union_declarations: HashMap<String, TableOrUnion>, |
| declarations: HashMap<String, String>, |
| } |
| |
| #[derive(Deserialize)] |
| pub struct TableOrUnion { |
| pub name: String, |
| pub strict: bool, |
| #[serde(deserialize_with = "hash_by_ordinal")] |
| pub members: HashMap<u64, TableOrUnionMember>, |
| } |
| named!(TableOrUnion); |
| |
| #[derive(Deserialize)] |
| pub struct TableOrUnionMember { |
| pub name: String, |
| #[serde(rename = "type")] |
| pub ty: Type, |
| pub ordinal: u64, |
| } |
| |
| #[derive(Deserialize)] |
| #[serde(try_from = "EnumExpanded")] |
| pub struct Enum { |
| pub name: String, |
| pub ty: Type, |
| pub strict: bool, |
| pub members: Vec<ValueMember>, |
| } |
| named!(Enum); |
| |
| #[derive(Deserialize)] |
| #[serde(try_from = "BitsExpanded")] |
| pub struct Bits { |
| pub name: String, |
| pub ty: Type, |
| pub strict: bool, |
| pub mask: u64, |
| pub members: Vec<ValueMember>, |
| } |
| named!(Bits); |
| |
| pub struct ValueMember { |
| pub name: String, |
| pub value: Value, |
| } |
| |
| #[derive(Deserialize)] |
| struct EnumExpanded { |
| name: String, |
| #[serde(rename = "type")] |
| ty: String, |
| strict: bool, |
| members: Vec<ValueMemberExpanded>, |
| } |
| |
| #[derive(Deserialize)] |
| struct BitsExpanded { |
| name: String, |
| #[serde(rename = "type")] |
| ty: Type, |
| strict: bool, |
| members: Vec<ValueMemberExpanded>, |
| mask: String, |
| } |
| |
| // We want to un-nest some of the nonsense in the bits declarations. this is how. |
| #[derive(Deserialize)] |
| struct ValueMemberExpanded { |
| name: String, |
| value: ValueBlock, |
| } |
| |
| #[derive(Deserialize)] |
| struct ValueBlock { |
| value: String, |
| } |
| |
| #[allow(dead_code)] // TODO(https://fxbug.dev/318827209) |
| #[derive(Debug)] |
| enum ValueConvertError { |
| FloatError(std::num::ParseFloatError), |
| IntError(std::num::ParseIntError), |
| BadPrimitive(String), |
| } |
| |
| impl From<std::num::ParseFloatError> for ValueConvertError { |
| fn from(item: std::num::ParseFloatError) -> ValueConvertError { |
| ValueConvertError::FloatError(item) |
| } |
| } |
| |
| impl From<std::num::ParseIntError> for ValueConvertError { |
| fn from(item: std::num::ParseIntError) -> ValueConvertError { |
| ValueConvertError::IntError(item) |
| } |
| } |
| |
| impl std::fmt::Display for ValueConvertError { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| std::fmt::Debug::fmt(self, f) |
| } |
| } |
| |
| fn convert_expanded_value_member( |
| ty: &Type, |
| container: &str, |
| members: Vec<ValueMemberExpanded>, |
| ) -> std::result::Result<Vec<ValueMember>, ValueConvertError> { |
| type ConverterType = dyn Fn(String) -> std::result::Result<Value, ValueConvertError>; |
| |
| let converter = match ty { |
| Type::U8 => (&|x: String| Ok(Value::U8(x.parse::<u8>()?))) as &ConverterType, |
| Type::U16 => (&|x: String| Ok(Value::U16(x.parse::<u16>()?))) as &ConverterType, |
| Type::U32 => (&|x: String| Ok(Value::U32(x.parse::<u32>()?))) as &ConverterType, |
| Type::U64 => (&|x: String| Ok(Value::U64(x.parse::<u64>()?))) as &ConverterType, |
| Type::I8 => (&|x: String| Ok(Value::I8(x.parse::<i8>()?))) as &ConverterType, |
| Type::I16 => (&|x: String| Ok(Value::I16(x.parse::<i16>()?))) as &ConverterType, |
| Type::I32 => (&|x: String| Ok(Value::I32(x.parse::<i32>()?))) as &ConverterType, |
| Type::I64 => (&|x: String| Ok(Value::I64(x.parse::<i64>()?))) as &ConverterType, |
| Type::F32 => (&|x: String| Ok(Value::F32(x.parse::<f32>()?))) as &ConverterType, |
| Type::F64 => (&|x: String| Ok(Value::F64(x.parse::<f64>()?))) as &ConverterType, |
| _ => return Err(ValueConvertError::BadPrimitive(container.to_owned())), |
| }; |
| |
| let mut result = Vec::new(); |
| |
| for member in members { |
| result.push(ValueMember { name: member.name, value: converter(member.value.value)? }); |
| } |
| |
| Ok(result) |
| } |
| |
| impl TryFrom<EnumExpanded> for Enum { |
| type Error = ValueConvertError; |
| |
| fn try_from(exp: EnumExpanded) -> std::result::Result<Enum, Self::Error> { |
| let (name, ty, strict, members) = (exp.name, exp.ty.into(), exp.strict, exp.members); |
| let members = convert_expanded_value_member(&ty, &name, members)?; |
| Ok(Enum { name, ty, strict, members }) |
| } |
| } |
| |
| impl TryFrom<BitsExpanded> for Bits { |
| type Error = ValueConvertError; |
| |
| fn try_from(exp: BitsExpanded) -> std::result::Result<Bits, Self::Error> { |
| let (name, ty, strict, members, mask) = |
| (exp.name, exp.ty, exp.strict, exp.members, exp.mask); |
| let members = convert_expanded_value_member(&ty, &name, members)?; |
| let mask = mask.parse::<u64>()?; |
| Ok(Bits { name, ty, strict, members, mask }) |
| } |
| } |
| |
| #[derive(Deserialize)] |
| pub struct Protocol { |
| pub name: String, |
| #[serde(deserialize_with = "hash_by_name_arc")] |
| pub methods: HashMap<String, Arc<Method>>, |
| #[serde(deserialize_with = "composed_protocols")] |
| pub composed_protocols: Vec<String>, |
| } |
| named!(Protocol); |
| |
| #[derive(Debug, Clone, Deserialize)] |
| pub struct Struct { |
| pub name: String, |
| pub members: Vec<Member>, |
| #[serde(rename = "type_shape_v2", deserialize_with = "extract_struct_size")] |
| pub size: usize, |
| } |
| named!(Struct); |
| |
| #[derive(Debug, Clone, Deserialize)] |
| pub struct Member { |
| pub name: String, |
| #[serde(rename = "type")] |
| pub ty: Type, |
| #[serde(rename = "field_shape_v2", deserialize_with = "extract_member_offset")] |
| pub offset: usize, |
| } |
| named!(Member); |
| |
| #[derive(Deserialize)] |
| struct MemberShape { |
| offset: usize, |
| } |
| |
| #[derive(Deserialize)] |
| struct TypeShape { |
| inline_size: usize, |
| } |
| |
| #[derive(Debug, Deserialize)] |
| pub struct Method { |
| pub name: String, |
| pub ordinal: u64, |
| pub strict: bool, |
| pub has_request: bool, |
| #[serde(rename = "maybe_request_payload")] |
| pub request: Option<Type>, |
| pub has_response: bool, |
| #[serde(rename = "maybe_response_payload")] |
| pub response: Option<Type>, |
| } |
| named!(Method); |
| |
| #[derive(Clone, Deserialize, Debug)] |
| #[serde(from = "TypeInfo")] |
| pub enum Type { |
| Unknown(TypeInfo), |
| UnknownString(String), |
| FrameworkError, |
| Identifier { name: String, nullable: bool }, |
| Bool, |
| U8, |
| U16, |
| U32, |
| U64, |
| I8, |
| I16, |
| I32, |
| I64, |
| F32, |
| F64, |
| Array(Box<Type>, usize), |
| Vector { ty: Box<Type>, nullable: bool, element_count: Option<usize> }, |
| String { nullable: bool, byte_count: Option<usize> }, |
| Handle { object_type: fidl::ObjectType, rights: fidl::Rights, nullable: bool }, |
| Request { identifier: String, rights: fidl::Rights, nullable: bool }, |
| } |
| |
| impl Type { |
| pub fn inline_size(&self, ns: &Namespace) -> Result<usize> { |
| use Type::*; |
| |
| match self { |
| Bool | U8 | I8 => Ok(1), |
| U16 | I16 => Ok(2), |
| FrameworkError | U32 | I32 | F32 | Handle { .. } | Request { .. } => Ok(4), |
| U64 | I64 | F64 => Ok(8), |
| Vector { .. } | String { .. } => Ok(16), |
| Array(a, b) => Ok(a.inline_size(ns)? * b), |
| Identifier { name, nullable } => match ns.lookup(name)? { |
| LookupResult::Bits(b) => b.ty.inline_size(ns), |
| LookupResult::Enum(e) => e.ty.inline_size(ns), |
| LookupResult::Struct(s) => Ok(if *nullable { 8 } else { s.size }), |
| LookupResult::Table(_) => Ok(16), |
| LookupResult::Union(_) => Ok(16), |
| LookupResult::Protocol(_) => Ok(4), |
| }, |
| Unknown(_) | UnknownString(_) => { |
| Err(Error::LibraryError("Cannot get size for unknown type.".to_owned())) |
| } |
| } |
| } |
| |
| pub fn is_resolved(&self, ns: &Namespace) -> bool { |
| match self { |
| Type::Unknown(_) | Type::UnknownString(_) => false, |
| Type::Identifier { name, .. } => ns.lookup(name).is_ok(), |
| _ => true, |
| } |
| } |
| } |
| |
| #[derive(Clone, Deserialize, Debug)] |
| pub struct TypeInfo { |
| pub kind: String, |
| #[serde(default)] |
| #[serde(rename = "obj_type")] |
| #[serde(deserialize_with = "object_type")] |
| pub object_type: Option<fidl::ObjectType>, |
| #[serde(default)] |
| #[serde(deserialize_with = "rights")] |
| pub rights: Option<fidl::Rights>, |
| pub identifier: Option<String>, |
| pub subtype: Option<String>, |
| pub element_type: Box<Option<TypeInfo>>, |
| pub element_count: Option<usize>, |
| pub maybe_element_count: Option<usize>, |
| #[serde(default)] |
| pub nullable: bool, |
| } |
| |
| impl From<TypeInfo> for Type { |
| fn from(info: TypeInfo) -> Type { |
| let nullable = info.nullable; |
| |
| if info.kind == "primitive" { |
| let subtype = if let Some(x) = info.subtype.clone() { |
| x |
| } else { |
| return Type::Unknown(info); |
| }; |
| match subtype.into() { |
| Type::UnknownString(_) => Type::Unknown(info), |
| ty @ _ => ty, |
| } |
| } else if info.kind == "vector" { |
| match *info.element_type { |
| Some(t) => Type::Vector { |
| ty: Box::new(t.into()), |
| nullable, |
| element_count: info.maybe_element_count, |
| }, |
| _ => Type::Unknown(info), |
| } |
| } else if info.kind == "array" { |
| if info.element_type.is_some() && info.element_count.is_some() { |
| Type::Array( |
| Box::new(info.element_type.unwrap().into()), |
| info.element_count.unwrap(), |
| ) |
| } else { |
| Type::Unknown(info) |
| } |
| } else if info.kind == "handle" { |
| if let Some(object_type) = info.object_type { |
| Type::Handle { |
| object_type, |
| rights: info.rights.unwrap_or(fidl::Rights::SAME_RIGHTS), |
| nullable, |
| } |
| } else { |
| Type::Unknown(info) |
| } |
| } else if info.kind == "identifier" { |
| if let Some(identifier) = info.identifier { |
| Type::Identifier { name: identifier, nullable } |
| } else { |
| Type::Unknown(info) |
| } |
| } else if info.kind == "string" { |
| Type::String { nullable, byte_count: info.maybe_element_count } |
| } else if info.kind == "request" { |
| if let Some(identifier) = info.subtype.clone() { |
| Type::Request { |
| identifier, |
| rights: info.rights.unwrap_or(fidl::Rights::CHANNEL_DEFAULT), |
| nullable: info.nullable, |
| } |
| } else { |
| Type::Unknown(info) |
| } |
| } else if info.kind == "internal" { |
| if info.subtype.as_deref() == Some("framework_error") { |
| Type::FrameworkError |
| } else { |
| Type::Unknown(info) |
| } |
| } else { |
| Type::Unknown(info) |
| } |
| } |
| } |
| |
| impl From<&str> for Type { |
| fn from(name: &str) -> Type { |
| match name.as_ref() { |
| "bool" => Type::Bool, |
| "uint8" => Type::U8, |
| "uint16" => Type::U16, |
| "uint32" => Type::U32, |
| "uint64" => Type::U64, |
| "int8" => Type::I8, |
| "int16" => Type::I16, |
| "int32" => Type::I32, |
| "int64" => Type::I64, |
| "float32" => Type::F32, |
| "float64" => Type::F64, |
| _ => Type::UnknownString(name.to_owned()), |
| } |
| } |
| } |
| |
| impl From<String> for Type { |
| fn from(name: String) -> Type { |
| name.as_str().into() |
| } |
| } |
| |
| pub enum LookupResult<'a> { |
| Bits(&'a Bits), |
| Enum(&'a Enum), |
| Protocol(&'a Protocol), |
| Struct(&'a Struct), |
| Table(&'a TableOrUnion), |
| Union(&'a TableOrUnion), |
| } |
| |
| /// A collection of loaded modules. |
| pub struct Namespace { |
| modules: HashMap<String, Module>, |
| methods_by_ordinal: HashMap<u64, (String, Weak<Method>)>, |
| } |
| |
| impl Namespace { |
| /// Create a new, empty namespace. |
| pub fn new() -> Self { |
| Namespace { modules: HashMap::new(), methods_by_ordinal: HashMap::new() } |
| } |
| |
| /// Load a module from the text of its FIDL JSON file. |
| pub fn load(&mut self, data: &str) -> Result<()> { |
| let new_mod: Module = serde_json::from_str(data)?; |
| |
| for protocol in new_mod.protocol_declarations.values() { |
| for method in protocol.methods.values() { |
| self.methods_by_ordinal |
| .insert(method.ordinal, (protocol.name(), Arc::downgrade(method))); |
| } |
| } |
| |
| self.modules.insert(new_mod.name.clone(), new_mod); |
| Ok(()) |
| } |
| |
| /// Look up a name in the loaded modules. |
| pub fn lookup(&self, name: &str) -> Result<LookupResult<'_>> { |
| let halves: Vec<_> = name.split('/').collect(); |
| |
| if halves.len() != 2 { |
| return Err(Error::LibraryError(format!( |
| "Wrong number of path components in {}, expected 2", |
| name |
| ))); |
| } |
| |
| let module: &Module = match self.modules.get(halves[0]) { |
| Some(x) => x, |
| None => return Err(Error::LibraryError(format!("Module {} not found!", halves[0]))), |
| }; |
| |
| match module.declarations.get(name).map(|x| x.as_ref()) { |
| Some("bits") => match module.bits_declarations.get(name) { |
| Some(x) => Ok(LookupResult::Bits(x)), |
| None => { |
| Err(Error::LibraryError(format!("{} not found in bits declarations!", name))) |
| } |
| }, |
| Some("enum") => match module.enum_declarations.get(name) { |
| Some(x) => Ok(LookupResult::Enum(x)), |
| None => { |
| Err(Error::LibraryError(format!("{} not found in enum declarations!", name))) |
| } |
| }, |
| Some("protocol") => match module.protocol_declarations.get(name) { |
| Some(x) => Ok(LookupResult::Protocol(x)), |
| None => Err(Error::LibraryError(format!( |
| "{} not found in protocol declarations!", |
| name |
| ))), |
| }, |
| Some("struct") => match module.struct_declarations.get(name) { |
| Some(x) => Ok(LookupResult::Struct(x)), |
| None => { |
| Err(Error::LibraryError(format!("{} not found in struct declarations!", name))) |
| } |
| }, |
| Some("table") => match module.table_declarations.get(name) { |
| Some(x) => Ok(LookupResult::Table(x)), |
| None => { |
| Err(Error::LibraryError(format!("{} not found in table declarations!", name))) |
| } |
| }, |
| Some("union") => match module.union_declarations.get(name) { |
| Some(x) => Ok(LookupResult::Union(x)), |
| None => { |
| Err(Error::LibraryError(format!("{} not found in union declarations!", name))) |
| } |
| }, |
| Some(x) => Err(Error::LibraryError(format!("{} has unknown type {}!", name, x))), |
| None => Err(Error::LibraryError(format!("{} not found in {}!", name, module.name))), |
| } |
| } |
| |
| /// Return whether a protocol inherits from another. |
| pub fn inherits(&self, a: &str, b: &str) -> bool { |
| if a == b { |
| return true; |
| } |
| |
| let Ok(LookupResult::Protocol(protocol)) = self.lookup(a) else { |
| return false; |
| }; |
| |
| for composed_protocol in protocol.composed_protocols.iter() { |
| if self.inherits(composed_protocol, b) { |
| return true; |
| } |
| } |
| |
| false |
| } |
| |
| /// Look up a method ordinal in the loaded modules. |
| pub fn lookup_method_ordinal(&self, ordinal: u64) -> Result<(String, Arc<Method>)> { |
| self.methods_by_ordinal |
| .get(&ordinal) |
| .and_then(|(x, y)| y.upgrade().map(|y| (x.clone(), y))) |
| .ok_or(Error::LibraryError(format!("No method with ordinal {}", ordinal))) |
| } |
| } |