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
use crate::{Error, Result, RootType, TupleSpecifier};
use winnow::{trace::trace, PResult, Parser};
/// A stem of a Solidity array type. It is either a root type, or a tuple type.
///
/// # Examples
///
/// ```
/// # use alloy_sol_type_parser::{TypeStem, RootType, TupleSpecifier};
/// let stem = TypeStem::parse("uint256")?;
/// assert_eq!(stem.span(), "uint256");
/// assert!(matches!(stem, TypeStem::Root(_)));
/// assert_eq!(stem.as_root(), Some(&RootType::parse("uint256").unwrap()));
///
/// let stem = TypeStem::parse("(uint256,bool)")?;
/// assert_eq!(stem.span(), "(uint256,bool)");
/// assert!(matches!(stem, TypeStem::Tuple(_)));
/// assert_eq!(
/// stem.as_tuple(),
/// Some(&TupleSpecifier::parse("(uint256,bool)").unwrap())
/// );
/// # Ok::<_, alloy_sol_type_parser::Error>(())
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TypeStem<'a> {
/// Root type.
Root(RootType<'a>),
/// Tuple type.
Tuple(TupleSpecifier<'a>),
}
impl<'a> TryFrom<&'a str> for TypeStem<'a> {
type Error = Error;
#[inline]
fn try_from(value: &'a str) -> Result<Self> {
Self::parse(value)
}
}
impl AsRef<str> for TypeStem<'_> {
#[inline]
fn as_ref(&self) -> &str {
self.span()
}
}
impl<'a> TypeStem<'a> {
/// Parse a type stem from a string.
#[inline]
pub fn parse(input: &'a str) -> Result<Self> {
if input.starts_with('(') || input.starts_with("tuple(") {
input.try_into().map(Self::Tuple)
} else {
input.try_into().map(Self::Root)
}
}
pub(crate) fn parser(input: &mut &'a str) -> PResult<Self> {
let name = "TypeStem";
if input.starts_with('(') || input.starts_with("tuple(") {
trace(name, TupleSpecifier::parser)
.parse_next(input)
.map(Self::Tuple)
} else {
trace(name, RootType::parser)
.parse_next(input)
.map(Self::Root)
}
}
/// Fallible conversion to a root type
#[inline]
pub const fn as_root(&self) -> Option<&RootType<'a>> {
match self {
Self::Root(root) => Some(root),
Self::Tuple(_) => None,
}
}
/// Fallible conversion to a tuple type
#[inline]
pub const fn as_tuple(&self) -> Option<&TupleSpecifier<'a>> {
match self {
Self::Root(_) => None,
Self::Tuple(tuple) => Some(tuple),
}
}
/// Returns the type stem as a string.
#[inline]
pub const fn span(&self) -> &'a str {
match self {
Self::Root(root) => root.span(),
Self::Tuple(tuple) => tuple.span(),
}
}
/// Returns true if the type is a basic Solidity type.
#[inline]
pub fn try_basic_solidity(&self) -> Result<()> {
match self {
Self::Root(root) => root.try_basic_solidity(),
Self::Tuple(tuple) => tuple.try_basic_solidity(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tuple() {
// empty tuple
assert_eq!(
TypeStem::parse("()"),
Ok(TypeStem::Tuple(TupleSpecifier {
span: "()",
types: vec![]
}))
);
TypeStem::parse("tuple(").unwrap_err();
assert_eq!(
TypeStem::parse("tuple()"),
Ok(TypeStem::Tuple(TupleSpecifier {
span: "tuple()",
types: vec![]
}))
);
// type named tuple
assert_eq!(
TypeStem::parse("tuple"),
Ok(TypeStem::Root(RootType::parse("tuple").unwrap()))
)
}
}