diff --git a/src/parse/context.rs b/src/parse/context.rs index fe3ff14..a717d8d 100644 --- a/src/parse/context.rs +++ b/src/parse/context.rs @@ -8,6 +8,8 @@ use crate::parse::{ proto::extensions::SimpleExtensionUri, text::simple_extensions::SimpleExtensions, Anchor, Parse, }; +use super::proto::extensions::{ExtensionFunction, ExtensionType, ExtensionTypeVariation}; + /// A parse context. /// /// Parsing Substrait data is context-sensitive. This trait provides methods @@ -38,6 +40,33 @@ pub trait Context { &self, anchor: &Anchor, ) -> Result<&SimpleExtensions, ContextError>; + + /// Add a [ExtensionFunction] to this context. Must return an error for duplicate + /// anchors, when the URI is not supported or if the definition does not contain a matching function with the given name. + /// + /// This function must eagerly resolve and parse the simple extension, returning an + /// error if either fails. + fn add_extension_function( + &mut self, + extension_function: &ExtensionFunction, + ) -> Result<(), ContextError>; + + /// Add an [ExtensionType] to this context. Must return an error for duplicate + /// anchors, when the URI is not supported or if the definition does not contain a matching function with the given name. + /// + /// This function must eagerly resolve and parse the simple extension, returning an + /// error if either fails. + fn add_extension_type(&mut self, extension: &ExtensionType) -> Result<(), ContextError>; + + /// Add a [ExtensionTypeVariation] to this context. Must return an error for duplicate + /// anchors, when the URI is not supported or if the definition does not contain a matching function with the given name. + /// + /// This function must eagerly resolve and parse the simple extension, returning an + /// error if either fails. + fn add_extension_type_variation( + &mut self, + extension_type_variation: &ExtensionTypeVariation, + ) -> Result<(), ContextError>; } /// Parse context errors. @@ -51,6 +80,18 @@ pub enum ContextError { #[error("duplicate anchor `{0}` for simple extension")] DuplicateSimpleExtension(Anchor), + /// Duplicate anchor for [ExtensionType]. + #[error("duplicate anchor `{0}` for extension_type")] + DuplicateExtensionType(Anchor), + + /// Duplicate anchor for [ExtensionFunction]. + #[error("duplicate anchor `{0}` for extension_function")] + DuplicateExtensionFunction(Anchor), + + /// Duplicate anchor for [ExtensionTypeVariation]. + #[error("duplicate anchor `{0}` for extension_type_variation")] + DuplicateExtensionTypeVariation(Anchor), + /// Unsupported simple extension URI. #[error("unsupported simple extension URI: {0}")] UnsupportedURI(String), @@ -61,8 +102,12 @@ pub(crate) mod tests { use std::collections::{hash_map::Entry, HashMap}; use crate::parse::{ - context::ContextError, proto::extensions::SimpleExtensionUri, - text::simple_extensions::SimpleExtensions, Anchor, + context::ContextError, + proto::extensions::{ + ExtensionFunction, ExtensionType, ExtensionTypeVariation, SimpleExtensionUri, + }, + text::simple_extensions::SimpleExtensions, + Anchor, }; /// A test context. @@ -72,6 +117,9 @@ pub(crate) mod tests { pub struct Context { empty_simple_extensions: SimpleExtensions, simple_extensions: HashMap, SimpleExtensionUri>, + extension_types: HashMap, ExtensionType>, + extension_functions: HashMap, ExtensionFunction>, + extension_type_variations: HashMap, ExtensionTypeVariation>, } impl Default for Context { @@ -79,6 +127,9 @@ pub(crate) mod tests { Self { empty_simple_extensions: SimpleExtensions {}, simple_extensions: Default::default(), + extension_types: Default::default(), + extension_functions: Default::default(), + extension_type_variations: Default::default(), } } } @@ -118,5 +169,56 @@ pub(crate) mod tests { .then_some(&self.empty_simple_extensions) .ok_or(ContextError::UndefinedSimpleExtension(*anchor)) } + + fn add_extension_function( + &mut self, + extension_function: &crate::parse::proto::extensions::ExtensionFunction, + ) -> Result<(), ContextError> { + match self.extension_functions.entry(extension_function.anchor()) { + Entry::Occupied(_) => Err(ContextError::DuplicateExtensionFunction( + extension_function.anchor(), + )), + Entry::Vacant(entry) => { + entry.insert(extension_function.clone()); + + Ok(()) + } + } + } + + fn add_extension_type( + &mut self, + extension_type: &crate::parse::proto::extensions::ExtensionType, + ) -> Result<(), ContextError> { + match self.extension_types.entry(extension_type.anchor()) { + Entry::Occupied(_) => Err(ContextError::DuplicateExtensionType( + extension_type.anchor(), + )), + Entry::Vacant(entry) => { + entry.insert(extension_type.clone()); + + Ok(()) + } + } + } + + fn add_extension_type_variation( + &mut self, + extension_type_variation: &crate::parse::proto::extensions::ExtensionTypeVariation, + ) -> Result<(), ContextError> { + match self + .extension_type_variations + .entry(extension_type_variation.anchor()) + { + Entry::Occupied(_) => Err(ContextError::DuplicateExtensionTypeVariation( + extension_type_variation.anchor(), + )), + Entry::Vacant(entry) => { + entry.insert(extension_type_variation.clone()); + + Ok(()) + } + } + } } } diff --git a/src/parse/proto/extensions/mod.rs b/src/parse/proto/extensions/mod.rs index 2527805..baca22e 100644 --- a/src/parse/proto/extensions/mod.rs +++ b/src/parse/proto/extensions/mod.rs @@ -2,5 +2,12 @@ //! Parsing of [proto::extensions] types. +mod simple_extension_declaration; mod simple_extension_uri; + +pub use simple_extension_declaration::declaration::SimpleExtensionDeclaration; +pub use simple_extension_declaration::extension_function::ExtensionFunction; +pub use simple_extension_declaration::extension_type::ExtensionType; +pub use simple_extension_declaration::extension_type_variation::ExtensionTypeVariation; +pub use simple_extension_declaration::mapping_type::MappingType; pub use simple_extension_uri::SimpleExtensionUri; diff --git a/src/parse/proto/extensions/simple_extension_declaration/declaration.rs b/src/parse/proto/extensions/simple_extension_declaration/declaration.rs new file mode 100644 index 0000000..99bcbce --- /dev/null +++ b/src/parse/proto/extensions/simple_extension_declaration/declaration.rs @@ -0,0 +1,101 @@ +use crate::{ + parse::{context::ContextError, Context, Parse}, + proto, +}; +use thiserror::Error; + +use super::mapping_type::MappingType; + +/// A parsed [`SimpleExtensionDeclaration`]. +#[derive(Clone, Debug, PartialEq)] +pub struct SimpleExtensionDeclaration { + /// The underlying mapping type of this extension declaration + pub mapping_type: MappingType, +} + +#[derive(Debug, PartialEq, Error)] +pub enum SimpleExtensionDeclarationError { + #[error("No Mapping Type specified on Extension Declaration.")] + MissingMappingType, + + /// Context error + #[error(transparent)] + Context(#[from] ContextError), +} + +impl Parse for proto::extensions::SimpleExtensionDeclaration { + type Parsed = SimpleExtensionDeclaration; + type Error = SimpleExtensionDeclarationError; + + fn parse(self, ctx: &mut C) -> Result { + let proto::extensions::SimpleExtensionDeclaration { mapping_type } = self; + + Ok(SimpleExtensionDeclaration { + mapping_type: mapping_type + .ok_or(SimpleExtensionDeclarationError::MissingMappingType)? + .parse(ctx)?, + }) + } +} + +impl From for proto::extensions::SimpleExtensionDeclaration { + fn from(declaration: SimpleExtensionDeclaration) -> Self { + let SimpleExtensionDeclaration { mapping_type } = declaration; + + proto::extensions::SimpleExtensionDeclaration { + mapping_type: Some(mapping_type.into()), + } + } +} + +#[cfg(test)] +mod test { + + use super::*; + use crate::parse::{ + context::tests::Context, proto::extensions::ExtensionFunction, typed::Name, Anchor, + }; + + #[test] + fn parse_from_protobuf() -> Result<(), SimpleExtensionDeclarationError> { + let declaration = proto::extensions::SimpleExtensionDeclaration { + mapping_type: Some( + proto::extensions::simple_extension_declaration::MappingType::ExtensionFunction( + proto::extensions::simple_extension_declaration::ExtensionFunction { + extension_uri_reference: 1, + function_anchor: 1, + name: "test_name".to_string(), + }, + ), + ), + }; + let simple_extension = declaration.parse(&mut Context::default())?; + + assert!(matches!( + simple_extension.mapping_type, + MappingType::ExtensionFunction(_) + )); + + Ok(()) + } + + #[test] + fn convert_from_parsed() { + let declaration = SimpleExtensionDeclaration { + mapping_type: MappingType::ExtensionFunction(ExtensionFunction { + anchor: Anchor::new(1), + name: Name::new("test".to_string()), + extension_uri_reference: Anchor::new(1), + }), + }; + + let protobuf_declaration = proto::extensions::SimpleExtensionDeclaration::from(declaration); + + assert!(matches!( + protobuf_declaration + .mapping_type + .expect("No mapping_type returned from declaration conversion."), + proto::extensions::simple_extension_declaration::MappingType::ExtensionFunction(_) + )); + } +} diff --git a/src/parse/proto/extensions/simple_extension_declaration/extension_function.rs b/src/parse/proto/extensions/simple_extension_declaration/extension_function.rs new file mode 100644 index 0000000..973bea8 --- /dev/null +++ b/src/parse/proto/extensions/simple_extension_declaration/extension_function.rs @@ -0,0 +1,144 @@ +use super::declaration::SimpleExtensionDeclarationError; +use crate::{ + parse::{proto::extensions::SimpleExtensionUri, typed::Name, Anchor, Context, Parse}, + proto, +}; + +/// A parsed [`ExtensionFunction`] +#[derive(Clone, Debug, PartialEq)] +pub struct ExtensionFunction { + /// The parsed [`Anchor`] for this [`ExtensionFunction`] + pub(crate) anchor: Anchor, + /// The parsed [`Name`] for this [`ExtensionFunction`] + pub(crate) name: Name, + /// The parsed [`SimpleExtensionUri`] for this [`ExtensionFunction`] + pub(crate) extension_uri_reference: Anchor, +} + +impl ExtensionFunction { + /// Returns the name of this [ExtensionType] + /// + /// See [proto::extensions::simple_extension_declaration::ExtensionType::name]. + pub fn name(&self) -> &Name { + &self.name + } + + /// Returns the anchor value of this [ExtensionType]. + /// + /// See [proto::extensions::simple_extension_declaration::ExtensionType]. + pub fn anchor(&self) -> Anchor { + self.anchor + } + + /// Returns the Extension URI Reference of this [ExtensionType]. + /// + /// See [proto::extensions::simple_extension_declaration::ExtensionType::extension_uri_reference]. + pub fn uri(&self) -> Anchor { + self.extension_uri_reference + } +} + +impl Parse for proto::extensions::simple_extension_declaration::ExtensionFunction { + type Parsed = ExtensionFunction; + type Error = SimpleExtensionDeclarationError; + + fn parse(self, ctx: &mut C) -> Result { + let proto::extensions::simple_extension_declaration::ExtensionFunction { + extension_uri_reference, + function_anchor, + name, + } = self; + + // Construct the parsed ExtensionFunction. + let extension_function = ExtensionFunction { + extension_uri_reference: Anchor::new(extension_uri_reference), + name: Name::new(name), + anchor: Anchor::new(function_anchor), + }; + + // Add the ExtensionFunction to the given context. + ctx.add_extension_function(&extension_function)?; + + Ok(extension_function) + } +} + +impl From + for proto::extensions::simple_extension_declaration::ExtensionFunction +{ + fn from(value: ExtensionFunction) -> Self { + let ExtensionFunction { + anchor, + name, + extension_uri_reference, + } = value; + + Self { + extension_uri_reference: extension_uri_reference.into_inner(), + function_anchor: anchor.into_inner(), + name: name.into_inner(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::parse::{ + context::{tests::Context, ContextError}, + Context as _, + }; + + #[test] + fn parse_extension_function() -> Result<(), SimpleExtensionDeclarationError> { + let extension_type = proto::extensions::simple_extension_declaration::ExtensionFunction { + function_anchor: 1, + extension_uri_reference: 2, + name: "test_extension_function".to_string(), + }; + let extension_type: ExtensionFunction = extension_type.parse(&mut Context::default())?; + assert_eq!(extension_type.anchor(), Anchor::new(1)); + assert_eq!( + extension_type.name(), + &Name::new("test_extension_function".to_string()) + ); + assert_eq!(extension_type.uri(), Anchor::new(2)); + assert_eq!(extension_type.extension_uri_reference, Anchor::new(2)); + Ok(()) + } + + #[test] + fn duplicate_simple_extension_function() { + let mut ctx = Context::default(); + let extension_type = proto::extensions::simple_extension_declaration::ExtensionFunction { + extension_uri_reference: 1, + function_anchor: 2, + name: "test_extension_function".to_string(), + }; + assert!(ctx.parse(extension_type.clone()).is_ok()); + assert_eq!( + ctx.parse(extension_type.clone()), + Err(SimpleExtensionDeclarationError::Context( + ContextError::DuplicateExtensionFunction(Anchor::new(2)) + )) + ); + } + + #[test] + fn can_get_protobuf_from_struct() { + let extension_type = ExtensionFunction { + extension_uri_reference: Anchor::new(1), + anchor: Anchor::new(1), + name: Name::new("test_extension_function".to_string()), + }; + + let protobuf_extension_function = + proto::extensions::simple_extension_declaration::ExtensionFunction::from( + extension_type, + ); + + assert_eq!(protobuf_extension_function.extension_uri_reference, 1); + assert_eq!(protobuf_extension_function.function_anchor, 1); + assert_eq!(protobuf_extension_function.name, "test_extension_function"); + } +} diff --git a/src/parse/proto/extensions/simple_extension_declaration/extension_type.rs b/src/parse/proto/extensions/simple_extension_declaration/extension_type.rs new file mode 100644 index 0000000..8f8eb78 --- /dev/null +++ b/src/parse/proto/extensions/simple_extension_declaration/extension_type.rs @@ -0,0 +1,141 @@ +use crate::parse::proto::extensions::SimpleExtensionUri; +use crate::parse::typed::Name; +use crate::parse::{Anchor, Context, Parse}; +use crate::proto; + +use super::declaration::SimpleExtensionDeclarationError; + +/// A parsed [`ExtensionType`] +#[derive(Clone, Debug, PartialEq)] +pub struct ExtensionType { + /// The parsed [`Anchor`] for this [`ExtensionType`] + pub(crate) anchor: Anchor, + /// The parsed [`Name`] for this [`ExtensionType`] + pub(crate) name: Name, + /// The parsed [`SimpleExtensionUri`] for this [`ExtensionType`] + pub(crate) extension_uri_reference: Anchor, +} + +impl ExtensionType { + /// Returns the name of this [ExtensionType] + /// + /// See [proto::extensions::simple_extension_declaration::ExtensionType::name]. + pub fn name(&self) -> &Name { + &self.name + } + + /// Returns the anchor value of this [ExtensionType]. + /// + /// See [proto::extensions::simple_extension_declaration::ExtensionType]. + pub fn anchor(&self) -> Anchor { + self.anchor + } + + /// Returns the Extension URI Reference of this [ExtensionType]. + /// + /// See [proto::extensions::simple_extension_declaration::ExtensionType::extension_uri_reference]. + pub fn uri(&self) -> Anchor { + self.extension_uri_reference + } +} + +impl Parse for proto::extensions::simple_extension_declaration::ExtensionType { + type Parsed = ExtensionType; + type Error = SimpleExtensionDeclarationError; + + fn parse(self, ctx: &mut C) -> Result { + let proto::extensions::simple_extension_declaration::ExtensionType { + extension_uri_reference, + type_anchor, + name, + } = self; + + // Construct the parsed ExtensionType. + let extension_type = ExtensionType { + extension_uri_reference: Anchor::new(extension_uri_reference), + name: Name::new(name), + anchor: Anchor::new(type_anchor), + }; + + // Add the ExtensionType to the given context. + ctx.add_extension_type(&extension_type)?; + + Ok(extension_type) + } +} + +impl From for proto::extensions::simple_extension_declaration::ExtensionType { + fn from(value: ExtensionType) -> Self { + let ExtensionType { + anchor, + name, + extension_uri_reference, + } = value; + + Self { + extension_uri_reference: extension_uri_reference.into_inner(), + type_anchor: anchor.into_inner(), + name: name.into_inner(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::parse::{ + context::{tests::Context, ContextError}, + Context as _, + }; + + #[test] + fn parse_extension_type() -> Result<(), SimpleExtensionDeclarationError> { + let extension_type = proto::extensions::simple_extension_declaration::ExtensionType { + type_anchor: 1, + extension_uri_reference: 2, + name: "test_extension_type".to_string(), + }; + let extension_type: ExtensionType = extension_type.parse(&mut Context::default())?; + assert_eq!(extension_type.anchor(), Anchor::new(1)); + assert_eq!( + extension_type.name(), + &Name::new("test_extension_type".to_string()) + ); + assert_eq!(extension_type.uri(), Anchor::new(2)); + assert_eq!(extension_type.extension_uri_reference, Anchor::new(2)); + Ok(()) + } + + #[test] + fn duplicate_simple_extension() { + let mut ctx = Context::default(); + let extension_type = proto::extensions::simple_extension_declaration::ExtensionType { + extension_uri_reference: 1, + type_anchor: 2, + name: "test_extension_type".to_string(), + }; + assert!(ctx.parse(extension_type.clone()).is_ok()); + assert_eq!( + ctx.parse(extension_type.clone()), + Err(SimpleExtensionDeclarationError::Context( + ContextError::DuplicateExtensionType(Anchor::new(2)) + )) + ); + } + + #[test] + fn can_get_protobuf_from_struct() { + let extension_type = ExtensionType { + extension_uri_reference: Anchor::new(1), + anchor: Anchor::new(1), + name: Name::new("test_extension_type".to_string()), + }; + + let protobuf_extension_type = + proto::extensions::simple_extension_declaration::ExtensionType::from(extension_type); + + assert_eq!(protobuf_extension_type.extension_uri_reference, 1); + assert_eq!(protobuf_extension_type.type_anchor, 1); + assert_eq!(protobuf_extension_type.name, "test_extension_type"); + } +} diff --git a/src/parse/proto/extensions/simple_extension_declaration/extension_type_variation.rs b/src/parse/proto/extensions/simple_extension_declaration/extension_type_variation.rs new file mode 100644 index 0000000..b3078f8 --- /dev/null +++ b/src/parse/proto/extensions/simple_extension_declaration/extension_type_variation.rs @@ -0,0 +1,150 @@ +use crate::parse::proto::extensions::SimpleExtensionUri; +use crate::parse::typed::Name; +use crate::parse::{Anchor, Context, Parse}; +use crate::proto; + +use super::declaration::SimpleExtensionDeclarationError; + +/// A parsed [`ExtensionTypeVariation`] +#[derive(Clone, Debug, PartialEq)] +pub struct ExtensionTypeVariation { + /// The parsed [`Anchor`] for this [`ExtensionTypeVariation`] + pub(crate) anchor: Anchor, + /// The parsed [`Name`] for this [`ExtensionTypeVariation`] + pub(crate) name: Name, + /// The parsed [`SimpleExtensionUri`] for this [`ExtensionTypeVariation`] + pub(crate) extension_uri_reference: Anchor, +} + +impl ExtensionTypeVariation { + /// Returns the name of this [ExtensionType] + /// + /// See [proto::extensions::simple_extension_declaration::ExtensionType::name]. + pub fn name(&self) -> &Name { + &self.name + } + + /// Returns the anchor value of this [ExtensionType]. + /// + /// See [proto::extensions::simple_extension_declaration::ExtensionType]. + pub fn anchor(&self) -> Anchor { + self.anchor + } + + /// Returns the Extension URI Reference of this [ExtensionType]. + /// + /// See [proto::extensions::simple_extension_declaration::ExtensionType::extension_uri_reference]. + pub fn uri(&self) -> Anchor { + self.extension_uri_reference + } +} + +impl Parse + for proto::extensions::simple_extension_declaration::ExtensionTypeVariation +{ + type Parsed = ExtensionTypeVariation; + type Error = SimpleExtensionDeclarationError; + + fn parse(self, ctx: &mut C) -> Result { + let proto::extensions::simple_extension_declaration::ExtensionTypeVariation { + extension_uri_reference, + type_variation_anchor, + name, + } = self; + + // Construct the parsed ExtensionTypeVariation. + let extension_type_variation = ExtensionTypeVariation { + extension_uri_reference: Anchor::new(extension_uri_reference), + name: Name::new(name), + anchor: Anchor::new(type_variation_anchor), + }; + + // Add the ExtensionTypeVariation to the given context. + ctx.add_extension_type_variation(&extension_type_variation)?; + + Ok(extension_type_variation) + } +} + +impl From + for proto::extensions::simple_extension_declaration::ExtensionTypeVariation +{ + fn from(value: ExtensionTypeVariation) -> Self { + let ExtensionTypeVariation { + anchor, + name, + extension_uri_reference, + } = value; + + Self { + extension_uri_reference: extension_uri_reference.into_inner(), + type_variation_anchor: anchor.into_inner(), + name: name.into_inner(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::parse::{ + context::{tests::Context, ContextError}, + Context as _, + }; + + #[test] + fn parse_extension_type_variation() -> Result<(), SimpleExtensionDeclarationError> { + let extension_type = + proto::extensions::simple_extension_declaration::ExtensionTypeVariation { + type_variation_anchor: 1, + extension_uri_reference: 2, + name: "test_extension_variation".to_string(), + }; + let extension_type: ExtensionTypeVariation = + extension_type.parse(&mut Context::default())?; + assert_eq!(extension_type.anchor(), Anchor::new(1)); + assert_eq!( + extension_type.name(), + &Name::new("test_extension_variation".to_string()) + ); + assert_eq!(extension_type.uri(), Anchor::new(2)); + assert_eq!(extension_type.extension_uri_reference, Anchor::new(2)); + Ok(()) + } + + #[test] + fn duplicate_simple_extension_variation() { + let mut ctx = Context::default(); + let extension_type = + proto::extensions::simple_extension_declaration::ExtensionTypeVariation { + extension_uri_reference: 1, + type_variation_anchor: 2, + name: "test_extension_var".to_string(), + }; + assert!(ctx.parse(extension_type.clone()).is_ok()); + assert_eq!( + ctx.parse(extension_type.clone()), + Err(SimpleExtensionDeclarationError::Context( + ContextError::DuplicateExtensionTypeVariation(Anchor::new(2)) + )) + ); + } + + #[test] + fn can_get_protobuf_from_struct() { + let extension_type = ExtensionTypeVariation { + extension_uri_reference: Anchor::new(1), + anchor: Anchor::new(1), + name: Name::new("test_extension_var".to_string()), + }; + + let protobuf_extension_type_variation = + proto::extensions::simple_extension_declaration::ExtensionTypeVariation::from( + extension_type, + ); + + assert_eq!(protobuf_extension_type_variation.extension_uri_reference, 1); + assert_eq!(protobuf_extension_type_variation.type_variation_anchor, 1); + assert_eq!(protobuf_extension_type_variation.name, "test_extension_var"); + } +} diff --git a/src/parse/proto/extensions/simple_extension_declaration/mapping_type.rs b/src/parse/proto/extensions/simple_extension_declaration/mapping_type.rs new file mode 100644 index 0000000..894d24c --- /dev/null +++ b/src/parse/proto/extensions/simple_extension_declaration/mapping_type.rs @@ -0,0 +1,168 @@ +use crate::{ + parse::{Context, Parse}, + proto, +}; + +use super::{ + declaration::SimpleExtensionDeclarationError, extension_function, extension_type, + extension_type_variation, +}; + +/// A parse [`MappingType`] +#[derive(Clone, Debug, PartialEq)] +pub enum MappingType { + /// A parsed [`ExtensionType`] + ExtensionType(extension_type::ExtensionType), + /// A parsed [`ExtensionTypeVariation`] + ExtensionTypeVariation(extension_type_variation::ExtensionTypeVariation), + /// A parsed [`ExtensionFunction`] + ExtensionFunction(extension_function::ExtensionFunction), +} + +impl Parse for proto::extensions::simple_extension_declaration::MappingType { + type Parsed = MappingType; + type Error = SimpleExtensionDeclarationError; + + fn parse(self, ctx: &mut C) -> Result { + Ok(match self { + proto::extensions::simple_extension_declaration::MappingType::ExtensionFunction(inner) => MappingType::ExtensionFunction(inner.parse(ctx)?), + proto::extensions::simple_extension_declaration::MappingType::ExtensionType(inner) => MappingType::ExtensionType(inner.parse(ctx)?), + proto::extensions::simple_extension_declaration::MappingType::ExtensionTypeVariation(inner) => MappingType::ExtensionTypeVariation(inner.parse(ctx)?), + }) + } +} + +impl From for proto::extensions::simple_extension_declaration::MappingType { + fn from(value: MappingType) -> Self { + match value { + MappingType::ExtensionFunction(inner) => Self::ExtensionFunction(inner.into()), + MappingType::ExtensionType(inner) => Self::ExtensionType(inner.into()), + MappingType::ExtensionTypeVariation(inner) => { + Self::ExtensionTypeVariation(inner.into()) + } + } + } +} + +#[cfg(test)] +mod tests { + + use super::*; + use crate::parse::{ + context::tests::Context, + proto::extensions::{ExtensionFunction, ExtensionType, ExtensionTypeVariation}, + typed::Name, + Anchor, + }; + + #[test] + fn parse_extension_function_mapping_type() -> Result<(), SimpleExtensionDeclarationError> { + let exntesion_function = + proto::extensions::simple_extension_declaration::MappingType::ExtensionFunction( + proto::extensions::simple_extension_declaration::ExtensionFunction { + function_anchor: 1, + extension_uri_reference: 2, + name: "test_value".to_string(), + }, + ); + + assert!(matches!( + exntesion_function.parse(&mut Context::default())?, + MappingType::ExtensionFunction(_) + )); + + Ok(()) + } + + #[test] + fn parse_extension_type_mapping_type() -> Result<(), SimpleExtensionDeclarationError> { + let extension_type = + proto::extensions::simple_extension_declaration::MappingType::ExtensionType( + proto::extensions::simple_extension_declaration::ExtensionType { + type_anchor: 1, + extension_uri_reference: 2, + name: "test_value".to_string(), + }, + ); + + assert!(matches!( + extension_type.parse(&mut Context::default())?, + MappingType::ExtensionType(_) + )); + + Ok(()) + } + + #[test] + fn parse_extension_variation_mapping_type() -> Result<(), SimpleExtensionDeclarationError> { + let extension_type_variation = + proto::extensions::simple_extension_declaration::MappingType::ExtensionTypeVariation( + proto::extensions::simple_extension_declaration::ExtensionTypeVariation { + type_variation_anchor: 1, + extension_uri_reference: 2, + name: "test_value".to_string(), + }, + ); + + assert!(matches!( + extension_type_variation.parse(&mut Context::default())?, + MappingType::ExtensionTypeVariation(_) + )); + + Ok(()) + } + + #[test] + fn can_convert_extension_function_mapping_type_from_protobuf() { + let extension_function = MappingType::ExtensionFunction(ExtensionFunction { + extension_uri_reference: Anchor::new(1), + anchor: Anchor::new(1), + name: Name::new("test".to_string()), + }); + + let protobuf_extension_function = + proto::extensions::simple_extension_declaration::MappingType::from(extension_function); + + assert!(matches!( + protobuf_extension_function, + proto::extensions::simple_extension_declaration::MappingType::ExtensionFunction(_) + )); + } + + #[test] + fn can_convert_extension_type_mapping_type_from_protobuf() { + let extension_type = MappingType::ExtensionType(ExtensionType { + extension_uri_reference: Anchor::new(1), + anchor: Anchor::new(1), + name: Name::new("test".to_string()), + }); + + let protobuf_extension = + proto::extensions::simple_extension_declaration::MappingType::from(extension_type); + + assert!(matches!( + protobuf_extension, + proto::extensions::simple_extension_declaration::MappingType::ExtensionType(_) + )); + } + + #[test] + fn can_convert_extension_type_variation_mapping_type_from_protobuf() { + let extension_type_variation = + MappingType::ExtensionTypeVariation(ExtensionTypeVariation { + extension_uri_reference: Anchor::new(1), + anchor: Anchor::new(1), + name: Name::new("test".to_string()), + }); + + let protobuf_extension_type_variation = + proto::extensions::simple_extension_declaration::MappingType::from( + extension_type_variation, + ); + + assert!(matches!( + protobuf_extension_type_variation, + proto::extensions::simple_extension_declaration::MappingType::ExtensionTypeVariation(_) + )); + } +} diff --git a/src/parse/proto/extensions/simple_extension_declaration/mod.rs b/src/parse/proto/extensions/simple_extension_declaration/mod.rs new file mode 100644 index 0000000..8a42f9b --- /dev/null +++ b/src/parse/proto/extensions/simple_extension_declaration/mod.rs @@ -0,0 +1,5 @@ +pub mod declaration; +pub mod extension_function; +pub mod extension_type; +pub mod extension_type_variation; +pub mod mapping_type; diff --git a/src/parse/typed.rs b/src/parse/typed.rs index 991e7b5..a3a59c3 100644 --- a/src/parse/typed.rs +++ b/src/parse/typed.rs @@ -79,3 +79,6 @@ impl hash::Hash for Typed { /// A generic anchor new type for the anchor mechanism used in Substrait data. pub type Anchor = Typed; + +/// A generic Name type for the named things inside of Substrait. +pub type Name = Typed;