substrait/parse/proto/extensions/
simple_extension_urn.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Parsing of [proto::extensions::SimpleExtensionUrn].
4
5use std::str::FromStr;
6
7use thiserror::Error;
8
9use crate::{
10    parse::{Anchor, Context, Parse, context::ContextError},
11    proto,
12    urn::{InvalidUrn, Urn},
13};
14
15/// A parsed [proto::extensions::SimpleExtensionUrn].
16#[derive(Clone, Debug, PartialEq)]
17pub struct SimpleExtensionUrn {
18    /// The urn of this simple extension.
19    urn: Urn,
20
21    /// The anchor value of this simple extension.
22    anchor: Anchor<Self>,
23}
24
25impl SimpleExtensionUrn {
26    /// Returns the urn of this simple extension.
27    ///
28    /// See [proto::extensions::SimpleExtensionUrn::urn].
29    pub fn urn(&self) -> &Urn {
30        &self.urn
31    }
32
33    /// Returns the anchor value of this simple extension.
34    ///
35    /// See [proto::extensions::SimpleExtensionUrn::extension_urn_anchor].
36    pub fn anchor(&self) -> Anchor<Self> {
37        self.anchor
38    }
39}
40
41/// Parse errors for [proto::extensions::SimpleExtensionUrn].
42#[derive(Debug, Error, PartialEq)]
43pub enum SimpleExtensionUrnError {
44    /// Invalid Urn
45    #[error("invalid urn")]
46    InvalidUrn(#[from] InvalidUrn),
47
48    /// Context error
49    #[error(transparent)]
50    Context(#[from] ContextError),
51}
52
53impl<C: Context> Parse<C> for proto::extensions::SimpleExtensionUrn {
54    type Parsed = SimpleExtensionUrn;
55    type Error = SimpleExtensionUrnError;
56
57    fn parse(self, ctx: &mut C) -> Result<Self::Parsed, Self::Error> {
58        let proto::extensions::SimpleExtensionUrn {
59            extension_urn_anchor: anchor,
60            urn,
61        } = self;
62
63        // The urn is is required and must be valid.
64        let urn = Urn::from_str(&urn)?;
65
66        // Construct the parsed simple extension urn.
67        let simple_extension_urn = SimpleExtensionUrn {
68            urn,
69            anchor: Anchor::new(anchor),
70        };
71
72        // Make sure the urn is supported by this parse context, resolves and
73        // parses, and the anchor is unique.
74        ctx.add_simple_extension_urn(&simple_extension_urn)?;
75
76        Ok(simple_extension_urn)
77    }
78}
79
80impl From<SimpleExtensionUrn> for proto::extensions::SimpleExtensionUrn {
81    fn from(simple_extension_urn: SimpleExtensionUrn) -> Self {
82        let SimpleExtensionUrn { urn, anchor } = simple_extension_urn;
83        proto::extensions::SimpleExtensionUrn {
84            urn: urn.to_string(),
85            extension_urn_anchor: anchor.into_inner(),
86        }
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93    use crate::parse::{Context as _, context::tests::Context};
94
95    #[test]
96    fn parse() -> Result<(), SimpleExtensionUrnError> {
97        let simple_extension_urn = proto::extensions::SimpleExtensionUrn {
98            extension_urn_anchor: 1,
99            urn: "extension:substrait-rs:test".to_string(),
100        };
101        let simple_extension_urn = simple_extension_urn.parse(&mut Context::default())?;
102        assert_eq!(simple_extension_urn.anchor(), Anchor::new(1));
103        assert_eq!(
104            simple_extension_urn.urn().to_string().as_str(),
105            "extension:substrait-rs:test"
106        );
107        Ok(())
108    }
109
110    #[test]
111    fn invalid_urn() {
112        let simple_extension_urn = proto::extensions::SimpleExtensionUrn::default();
113        assert_eq!(
114            simple_extension_urn.parse(&mut Context::default()),
115            Err(SimpleExtensionUrnError::InvalidUrn(InvalidUrn))
116        );
117        let simple_extension_urn = proto::extensions::SimpleExtensionUrn {
118            extension_urn_anchor: 1,
119            urn: "urn::".to_string(),
120        };
121        assert_eq!(
122            simple_extension_urn.parse(&mut Context::default()),
123            Err(SimpleExtensionUrnError::InvalidUrn(InvalidUrn))
124        );
125    }
126
127    #[test]
128    fn duplicate_simple_extension() {
129        let mut ctx = Context::default();
130        let simple_extension_urn = proto::extensions::SimpleExtensionUrn {
131            extension_urn_anchor: 1,
132            urn: "extension:substrait-rs:test".to_string(),
133        };
134        assert!(ctx.parse(simple_extension_urn.clone()).is_ok());
135        assert_eq!(
136            ctx.parse(simple_extension_urn),
137            Err(SimpleExtensionUrnError::Context(
138                ContextError::DuplicateSimpleExtension(Anchor::new(1))
139            ))
140        );
141    }
142}