summaryrefslogtreecommitdiffstats
path: root/vendor/const-oid/src/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/const-oid/src/parser.rs')
-rw-r--r--vendor/const-oid/src/parser.rs112
1 files changed, 112 insertions, 0 deletions
diff --git a/vendor/const-oid/src/parser.rs b/vendor/const-oid/src/parser.rs
new file mode 100644
index 000000000..6f875faaa
--- /dev/null
+++ b/vendor/const-oid/src/parser.rs
@@ -0,0 +1,112 @@
+//! OID string parser with `const` support.
+
+use crate::{encoder::Encoder, Arc, Error, ObjectIdentifier, Result};
+
+/// Const-friendly OID string parser.
+///
+/// Parses an OID from the dotted string representation.
+#[derive(Debug)]
+pub(crate) struct Parser {
+ /// Current arc in progress
+ current_arc: Arc,
+
+ /// BER/DER encoder
+ encoder: Encoder,
+}
+
+impl Parser {
+ /// Parse an OID from a dot-delimited string e.g. `1.2.840.113549.1.1.1`
+ pub(crate) const fn parse(s: &str) -> Result<Self> {
+ let bytes = s.as_bytes();
+
+ if bytes.is_empty() {
+ return Err(Error::Empty);
+ }
+
+ match bytes[0] {
+ b'0'..=b'9' => Self {
+ current_arc: 0,
+ encoder: Encoder::new(),
+ }
+ .parse_bytes(bytes),
+ actual => Err(Error::DigitExpected { actual }),
+ }
+ }
+
+ /// Finish parsing, returning the result
+ pub(crate) const fn finish(self) -> Result<ObjectIdentifier> {
+ self.encoder.finish()
+ }
+
+ /// Parse the remaining bytes
+ const fn parse_bytes(mut self, bytes: &[u8]) -> Result<Self> {
+ match bytes {
+ // TODO(tarcieri): use `?` when stable in `const fn`
+ [] => match self.encoder.arc(self.current_arc) {
+ Ok(encoder) => {
+ self.encoder = encoder;
+ Ok(self)
+ }
+ Err(err) => Err(err),
+ },
+ // TODO(tarcieri): checked arithmetic
+ #[allow(clippy::integer_arithmetic)]
+ [byte @ b'0'..=b'9', remaining @ ..] => {
+ let digit = byte.saturating_sub(b'0');
+ self.current_arc = self.current_arc * 10 + digit as Arc;
+ self.parse_bytes(remaining)
+ }
+ [b'.', remaining @ ..] => {
+ if remaining.is_empty() {
+ return Err(Error::TrailingDot);
+ }
+
+ // TODO(tarcieri): use `?` when stable in `const fn`
+ match self.encoder.arc(self.current_arc) {
+ Ok(encoder) => {
+ self.encoder = encoder;
+ self.current_arc = 0;
+ self.parse_bytes(remaining)
+ }
+ Err(err) => Err(err),
+ }
+ }
+ [byte, ..] => Err(Error::DigitExpected { actual: *byte }),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::Parser;
+ use crate::Error;
+
+ #[test]
+ fn parse() {
+ let oid = Parser::parse("1.23.456").unwrap().finish().unwrap();
+ assert_eq!(oid, "1.23.456".parse().unwrap());
+ }
+
+ #[test]
+ fn reject_empty_string() {
+ assert_eq!(Parser::parse("").err().unwrap(), Error::Empty);
+ }
+
+ #[test]
+ fn reject_non_digits() {
+ assert_eq!(
+ Parser::parse("X").err().unwrap(),
+ Error::DigitExpected { actual: b'X' }
+ );
+
+ assert_eq!(
+ Parser::parse("1.2.X").err().unwrap(),
+ Error::DigitExpected { actual: b'X' }
+ );
+ }
+
+ #[test]
+ fn reject_trailing_dot() {
+ assert_eq!(Parser::parse("1.23.").err().unwrap(), Error::TrailingDot);
+ }
+}