1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
// Copyright 2020 - developers of the `grammers` project.
// Copyright 2022 - developers of the `tdlib-rs` project.
// Copyright 2024 - developers of the `tgt` and `tdlib-rs` projects.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::fmt;
use std::str::FromStr;
use crate::errors::ParamParseError;
/// The type of a definition or a parameter.
#[derive(Debug, PartialEq)]
pub struct Type {
/// The name of the type.
pub name: String,
/// Whether this type is bare or boxed.
pub bare: bool,
/// If the type has a generic argument, which is its type.
pub generic_arg: Option<Box<Type>>,
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name)?;
if let Some(generic_arg) = &self.generic_arg {
write!(f, "<{}>", generic_arg)?;
}
Ok(())
}
}
impl FromStr for Type {
type Err = ParamParseError;
/// Parses a type.
///
/// # Examples
///
/// ```
/// use tdlib_rs_parser::tl::Type;
///
/// assert!("vector<int>".parse::<Type>().is_ok());
/// ```
fn from_str(ty: &str) -> Result<Self, Self::Err> {
// Parse `type<generic_arg>`
let (ty, generic_arg) = if let Some(pos) = ty.find('<') {
if !ty.ends_with('>') {
return Err(ParamParseError::InvalidGeneric);
}
(
&ty[..pos],
Some(Box::new(Type::from_str(&ty[pos + 1..ty.len() - 1])?)),
)
} else {
(ty, None)
};
if ty.is_empty() {
return Err(ParamParseError::Empty);
}
// Safe to unwrap because we just checked is not empty
let bare = ty.chars().next().unwrap().is_ascii_lowercase();
Ok(Self {
name: ty.into(),
bare,
generic_arg,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_empty_simple() {
assert_eq!(Type::from_str(""), Err(ParamParseError::Empty));
}
#[test]
fn check_simple() {
assert_eq!(
Type::from_str("foo"),
Ok(Type {
name: "foo".into(),
bare: true,
generic_arg: None,
})
);
}
#[test]
fn check_empty() {
assert_eq!(Type::from_str(""), Err(ParamParseError::Empty));
}
#[test]
fn check_bare() {
assert!(matches!(Type::from_str("foo"), Ok(Type { bare: true, .. })));
assert!(matches!(
Type::from_str("Foo"),
Ok(Type { bare: false, .. })
));
}
#[test]
fn check_generic_arg() {
assert!(matches!(
Type::from_str("foo"),
Ok(Type {
generic_arg: None,
..
})
));
assert!(match Type::from_str("foo<bar>") {
Ok(Type {
generic_arg: Some(x),
..
}) => *x == "bar".parse().unwrap(),
_ => false,
});
assert!(match Type::from_str("foo<bar>") {
Ok(Type {
generic_arg: Some(x),
..
}) => *x == "bar".parse().unwrap(),
_ => false,
});
assert!(match Type::from_str("foo<bar<baz>>") {
Ok(Type {
generic_arg: Some(x),
..
}) => *x == "bar<baz>".parse().unwrap(),
_ => false,
});
}
}