From 80f317a1eb3b2fa8b938efc8a290a6df4af20a01 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 13 Feb 2020 11:24:29 +0100 Subject: [PATCH] feat(interface-types) Ensure `ast::Type` is always well-formed. As @MarkMcCaskey noted, `Type` can be corrupted because `field_names` and `field_types` must have the same length. This patch removes the public visibility, and adds methods like `new`, `add_field`, `field_names` and `field_types` to encapsulate `Type` internal data. --- src/ast.rs | 40 ++++++++++++++++++++++++++++++++++++++-- src/decoders/binary.rs | 36 ++++++++++++++++-------------------- 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 4adf2f0..d8b82f5 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -87,10 +87,46 @@ pub struct Type<'input> { pub name: &'input str, /// The field names. - pub fields: Vec<&'input str>, + field_names: Vec<&'input str>, /// The field types. - pub types: Vec, + field_types: Vec, +} + +impl<'input> Type<'input> { + /// Creates a new `Type`. + /// + /// The constructor panics if there is the length of `names` is + /// different than the length of `types`. + pub fn new(type_name: &'input str, names: Vec<&'input str>, types: Vec) -> Self { + assert_eq!( + names.len(), + types.len(), + "There must be the same number of field names than field types." + ); + + Self { + name: type_name, + field_names: names, + field_types: types, + } + } + + /// Adds a new field to the type. + pub fn add_field(&mut self, name: &'input str, ty: InterfaceType) { + self.field_names.push(name); + self.field_types.push(ty); + } + + /// Returns the field names. + pub fn field_names(&self) -> &Vec<&'input str> { + &self.field_names + } + + /// Returns the field types. + pub fn field_types(&self) -> &Vec { + &self.field_types + } } /// Represents an adapter. diff --git a/src/decoders/binary.rs b/src/decoders/binary.rs index afa549a..027e8e5 100644 --- a/src/decoders/binary.rs +++ b/src/decoders/binary.rs @@ -293,11 +293,7 @@ fn types<'input, E: ParseError<&'input [u8]>>( consume!((input, type_fields) = list(input, string)?); consume!((input, type_types) = list(input, ty)?); - types.push(Type { - name: type_name, - fields: type_fields, - types: type_types, - }); + types.push(Type::new(type_name, type_fields, type_types)); } Ok((input, types)) @@ -479,11 +475,11 @@ fn forwards<'input, E: ParseError<&'input [u8]>>( /// input_types: vec![InterfaceType::I32], /// output_types: vec![InterfaceType::I32], /// }], -/// types: vec![Type { -/// name: "ab", -/// fields: vec!["cd", "e"], -/// types: vec![InterfaceType::I32, InterfaceType::I32], -/// }], +/// types: vec![Type::new( +/// "ab", +/// vec!["cd", "e"], +/// vec![InterfaceType::I32, InterfaceType::I32], +/// )], /// imports: vec![Import { /// namespace: "a", /// name: "b", @@ -728,11 +724,11 @@ mod tests { ]; let output = Ok(( &[] as &[u8], - vec![Type { - name: "ab", - fields: vec!["cd", "e"], - types: vec![InterfaceType::I32, InterfaceType::I32], - }], + vec![Type::new( + "ab", + vec!["cd", "e"], + vec![InterfaceType::I32, InterfaceType::I32], + )], )); assert_eq!(types::<()>(input), output); @@ -913,11 +909,11 @@ mod tests { input_types: vec![InterfaceType::I32], output_types: vec![InterfaceType::I32], }], - types: vec![Type { - name: "ab", - fields: vec!["cd", "e"], - types: vec![InterfaceType::I32, InterfaceType::I32], - }], + types: vec![Type::new( + "ab", + vec!["cd", "e"], + vec![InterfaceType::I32, InterfaceType::I32], + )], imports: vec![Import { namespace: "a", name: "b",