blob: 383a36bb04172d2fac1d8c9e53ebf083acf8a14b [file] [log] [blame]
// 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.
// Based on https://fuchsia.googlesource.com/fuchsia/+/HEAD/zircon/system/host/fidl/schema.json
use {
lazy_static::lazy_static,
regex::Regex,
serde::{Deserialize, Deserializer},
serde_derive::{Deserialize, Serialize},
std::collections::BTreeMap,
};
lazy_static! {
pub static ref IDENTIFIER_RE: Regex =
Regex::new(r#"^[A-Za-z]([_A-Za-z0-9]*[A-Za-z0-9])?$"#).unwrap();
pub static ref COMPOUND_IDENTIFIER_RE: Regex =
Regex::new(r#"([_A-Za-z][_A-Za-z0-9]*-)*[_A-Za-z][_A-Za-z0-9]*/[_A-Za-z][_A-Za-z0-9]*"#)
.unwrap();
pub static ref LIBRARY_IDENTIFIER_RE: Regex =
Regex::new(r#"^[a-z][a-z0-9]*(\.[a-z][a-z0-9]*)*$"#).unwrap();
pub static ref VERSION_RE: Regex = Regex::new(r#"^[0-9]+\.[0-9]+\.[0-9]+$"#).unwrap();
}
#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Ordinal(#[serde(deserialize_with = "validate_ordinal")] pub u32);
/// Validates that ordinal is non-zero.
fn validate_ordinal<'de, D>(deserializer: D) -> Result<u32, D::Error>
where
D: Deserializer<'de>,
{
let ordinal = u32::deserialize(deserializer)?;
if ordinal == 0 {
return Err(serde::de::Error::custom("Ordinal must not be equal to 0"));
}
Ok(ordinal)
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[repr(transparent)]
pub struct Count(pub u32);
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Identifier(#[serde(deserialize_with = "validate_identifier")] pub String);
fn validate_identifier<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'de>,
{
let id = String::deserialize(deserializer)?;
if !IDENTIFIER_RE.is_match(&id) {
return Err(serde::de::Error::custom(format!("Invalid identifier: {}", id)));
}
Ok(id)
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(transparent)]
pub struct CompoundIdentifier(
#[serde(deserialize_with = "validate_compound_identifier")] pub String,
);
fn validate_compound_identifier<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'de>,
{
let id = String::deserialize(deserializer)?;
if !COMPOUND_IDENTIFIER_RE.is_match(&id) {
return Err(serde::de::Error::custom(format!("Invalid compound identifier: {}", id)));
}
Ok(id)
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct LibraryIdentifier(#[serde(deserialize_with = "validate_library_identifier")] pub String);
fn validate_library_identifier<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'de>,
{
let id = String::deserialize(deserializer)?;
if !LIBRARY_IDENTIFIER_RE.is_match(&id) {
return Err(serde::de::Error::custom(format!("Invalid library identifier: {}", id)));
}
Ok(id)
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Version(#[serde(deserialize_with = "validate_version")] pub String);
fn validate_version<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'de>,
{
let version = String::deserialize(deserializer)?;
if !VERSION_RE.is_match(&version) {
return Err(serde::de::Error::custom(format!("Invalid version: {}", version)));
}
Ok(version)
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Declaration {
Const,
Enum,
Interface,
Struct,
Table,
Union,
XUnion,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct DeclarationsMap(pub BTreeMap<CompoundIdentifier, Declaration>);
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Library {
pub name: LibraryIdentifier,
pub declarations: DeclarationsMap,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Location {
pub filename: String,
pub line: u32,
pub column: u32,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum HandleSubtype {
Handle,
Process,
Thread,
Vmo,
Channel,
Event,
Port,
Interrupt,
Debuglog,
Socket,
Resource,
Eventpair,
Job,
Vmar,
Fifo,
Guest,
Timer,
Bti,
Profile,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum IntegerType {
Int8,
Int16,
Int32,
Int64,
Uint8,
Uint16,
Uint32,
Uint64,
}
// TODO(surajmalhotra): Implement conversion begtween IntegerType and PrimitiveSubtype.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PrimitiveSubtype {
Bool,
Float32,
Float64,
Int8,
Int16,
Int32,
Int64,
Uint8,
Uint16,
Uint32,
Uint64,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum Type {
Array {
element_type: Box<Type>,
element_count: Count,
},
Vector {
element_type: Box<Type>,
maybe_element_count: Option<Count>,
nullable: bool,
},
#[serde(rename = "string")]
Str {
maybe_element_count: Option<Count>,
nullable: bool,
},
Handle {
subtype: HandleSubtype,
nullable: bool,
},
Request {
subtype: CompoundIdentifier,
nullable: bool,
},
Primitive {
subtype: PrimitiveSubtype,
},
Identifier {
identifier: CompoundIdentifier,
nullable: bool,
},
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum Literal {
#[serde(rename = "string")]
Str {
value: String,
},
Numeric {
value: String,
},
True,
False,
#[serde(rename = "default")]
_Default,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum Constant {
Identifier { identifier: CompoundIdentifier },
Literal { literal: Literal },
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Const {
pub name: CompoundIdentifier,
pub location: Option<Location>,
#[serde(rename = "type")]
pub _type: Type,
pub value: Constant,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct EnumMember {
pub name: Identifier,
pub location: Option<Location>,
pub maybe_attributes: Option<Vec<Attribute>>,
pub value: Constant,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Enum {
pub maybe_attributes: Option<Vec<Attribute>>,
pub name: CompoundIdentifier,
pub location: Option<Location>,
#[serde(rename = "type")]
pub _type: IntegerType,
pub members: Vec<EnumMember>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Attribute {
pub name: String,
pub value: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct MethodParameter {
#[serde(rename = "type")]
pub _type: Type,
pub name: Identifier,
pub location: Option<Location>,
pub size: Count,
pub max_out_of_line: Count,
pub alignment: Count,
pub offset: Count,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Method {
pub maybe_attributes: Option<Vec<Attribute>>,
pub ordinal: Ordinal,
pub generated_ordinal: Ordinal,
pub name: Identifier,
pub location: Option<Location>,
pub has_request: bool,
pub maybe_request: Option<Vec<MethodParameter>>,
pub maybe_request_size: Option<Count>,
pub maybe_request_alignment: Option<Count>,
pub has_response: bool,
pub maybe_response: Option<Vec<MethodParameter>>,
pub maybe_response_size: Option<Count>,
pub maybe_response_alignment: Option<Count>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Interface {
pub maybe_attributes: Option<Vec<Attribute>>,
pub name: CompoundIdentifier,
pub location: Option<Location>,
pub methods: Vec<Method>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct StructMember {
#[serde(rename = "type")]
pub _type: Type,
pub name: Identifier,
pub location: Option<Location>,
pub size: Count,
pub max_out_of_line: Count,
pub alignment: Count,
pub offset: Count,
pub maybe_attributes: Option<Vec<Attribute>>,
pub maybe_default_value: Option<Constant>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Struct {
pub max_handles: Option<Count>,
pub maybe_attributes: Option<Vec<Attribute>>,
pub name: CompoundIdentifier,
pub location: Option<Location>,
pub anonymous: Option<bool>,
pub members: Vec<StructMember>,
pub size: Count,
pub max_out_of_line: Count,
}
#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct TableMember {
pub ordinal: Ordinal,
pub reserved: bool,
#[serde(rename = "type")]
pub _type: Option<Type>,
pub name: Option<Identifier>,
pub location: Option<Location>,
pub size: Option<Count>,
pub max_out_of_line: Option<Count>,
pub alignment: Option<Count>,
pub offset: Option<Count>,
pub maybe_default_value: Option<Constant>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Table {
pub max_handles: Option<Count>,
pub maybe_attributes: Option<Vec<Attribute>>,
pub name: CompoundIdentifier,
pub location: Option<Location>,
pub members: Vec<TableMember>,
pub size: Count,
pub max_out_of_line: Count,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct UnionMember {
#[serde(rename = "type")]
pub _type: Type,
pub name: Identifier,
pub location: Option<Location>,
pub size: Count,
pub max_out_of_line: Count,
pub alignment: Count,
pub offset: Count,
pub maybe_attributes: Option<Vec<Attribute>>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Union {
pub max_handles: Option<Count>,
pub maybe_attributes: Option<Vec<Attribute>>,
pub name: CompoundIdentifier,
pub location: Option<Location>,
pub members: Vec<UnionMember>,
pub size: Count,
pub max_out_of_line: Count,
pub alignment: Count,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct XUnionMember {
pub ordinal: Ordinal,
#[serde(rename = "type")]
pub _type: Type,
pub name: Identifier,
pub location: Option<Location>,
pub size: Count,
pub max_out_of_line: Count,
pub alignment: Count,
pub offset: Count,
pub maybe_attributes: Option<Vec<Attribute>>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct XUnion {
pub max_handles: Option<Count>,
pub maybe_attributes: Option<Vec<Attribute>>,
pub name: CompoundIdentifier,
pub location: Option<Location>,
pub members: Vec<XUnionMember>,
pub size: Count,
pub max_out_of_line: Count,
pub alignment: Count,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Ir {
pub version: Version,
pub name: LibraryIdentifier,
pub library_dependencies: Vec<Library>,
pub const_declarations: Vec<Const>,
pub enum_declarations: Vec<Enum>,
pub interface_declarations: Vec<Interface>,
pub struct_declarations: Vec<Struct>,
pub table_declarations: Vec<Table>,
pub union_declarations: Vec<Union>,
pub xunion_declarations: Vec<XUnion>,
pub declaration_order: Vec<CompoundIdentifier>,
pub declarations: DeclarationsMap,
}