use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
use core::str::FromStr;
use crate::helper::{compare_encodings, Helper, NestingLevel};
use crate::parse::{ErrorKind, ParseError, Parser};
use crate::Encoding;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive] pub enum EncodingBox {
Char,
Short,
Int,
Long,
LongLong,
UChar,
UShort,
UInt,
ULong,
ULongLong,
Float,
Double,
LongDouble,
FloatComplex,
DoubleComplex,
LongDoubleComplex,
Bool,
Void,
String,
Object,
Block,
Class,
Sel,
Unknown,
BitField(u8, Option<Box<(u64, Self)>>),
Pointer(Box<Self>),
Atomic(Box<Self>),
Array(u64, Box<Self>),
Struct(String, Vec<Self>),
Union(String, Vec<Self>),
None,
}
impl EncodingBox {
pub const C_LONG: Self = match Encoding::C_LONG {
Encoding::Long => Self::Long,
Encoding::LongLong => Self::LongLong,
_ => unreachable!(),
};
pub const C_ULONG: Self = match Encoding::C_ULONG {
Encoding::ULong => Self::ULong,
Encoding::ULongLong => Self::ULongLong,
_ => unreachable!(),
};
pub fn from_start_of_str(s: &mut &str) -> Result<Self, ParseError> {
let mut parser = Parser::new(s);
parser.strip_leading_qualifiers();
match parser.parse_encoding_or_none() {
Err(ErrorKind::Unknown(b'0'..=b'9')) => {
let remaining = parser.remaining();
*s = remaining;
Ok(EncodingBox::None)
}
Err(err) => Err(ParseError::new(parser, err)),
Ok(encoding) => {
let remaining = parser.remaining();
*s = remaining;
Ok(encoding)
}
}
}
}
impl fmt::Display for EncodingBox {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Helper::from_box(self).fmt(f, NestingLevel::new())
}
}
impl PartialEq<Encoding> for EncodingBox {
fn eq(&self, other: &Encoding) -> bool {
compare_encodings(self, other, NestingLevel::new(), true)
}
}
impl PartialEq<EncodingBox> for Encoding {
fn eq(&self, other: &EncodingBox) -> bool {
other.eq(self)
}
}
impl FromStr for EncodingBox {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parser = Parser::new(s);
parser.strip_leading_qualifiers();
parser
.parse_encoding_or_none()
.and_then(|enc| parser.expect_empty().map(|()| enc))
.map_err(|err| ParseError::new(parser, err))
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::ToString;
use alloc::vec;
#[test]
fn eq_encodings() {
let enc1 = Encoding::Char;
let enc2 = EncodingBox::Char;
let enc3 = EncodingBox::String;
assert_eq!(enc1, enc2);
assert_ne!(enc1, enc3);
}
#[test]
fn eq_complex_encodings() {
let enc1 = Encoding::Atomic(&Encoding::Struct(
"test",
&[Encoding::Array(2, &Encoding::Int)],
));
let enc2 = EncodingBox::Atomic(Box::new(EncodingBox::Struct(
"test".to_string(),
vec![EncodingBox::Array(2, Box::new(EncodingBox::Int))],
)));
let enc3 = EncodingBox::Atomic(Box::new(EncodingBox::Struct(
"test".to_string(),
vec![EncodingBox::Array(2, Box::new(EncodingBox::Char))],
)));
assert_eq!(enc1, enc2);
assert_ne!(enc1, enc3);
}
#[test]
fn struct_nested_in_pointer() {
let enc1 = EncodingBox::Struct("test".to_string(), vec![EncodingBox::Char]);
let enc2 = EncodingBox::Struct("test".to_string(), vec![EncodingBox::Int]);
const ENC3A: Encoding = Encoding::Struct("test", &[Encoding::Char]);
assert_ne!(enc1, enc2);
assert!(ENC3A.equivalent_to_box(&enc1));
assert!(!ENC3A.equivalent_to_box(&enc2));
let enc1 = EncodingBox::Pointer(Box::new(enc1));
let enc2 = EncodingBox::Pointer(Box::new(enc2));
const ENC3B: Encoding = Encoding::Pointer(&ENC3A);
assert_ne!(enc1, enc2);
assert!(ENC3B.equivalent_to_box(&enc1));
assert!(!ENC3B.equivalent_to_box(&enc2));
let enc1 = EncodingBox::Pointer(Box::new(enc1));
let enc2 = EncodingBox::Pointer(Box::new(enc2));
const ENC3C: Encoding = Encoding::Pointer(&ENC3B);
assert_ne!(enc1, enc2);
assert!(ENC3C.equivalent_to_box(&enc1));
assert!(ENC3C.equivalent_to_box(&enc2), "now they're equivalent");
}
#[test]
fn parse_atomic_struct() {
let expected = EncodingBox::Atomic(Box::new(EncodingBox::Atomic(Box::new(
EncodingBox::Struct("a".into(), vec![]),
))));
let actual = EncodingBox::from_str("AA{a=}").unwrap();
assert_eq!(expected, actual);
assert_eq!(expected.to_string(), "AA{a}");
let actual = EncodingBox::from_str("AA{a}").unwrap();
assert_eq!(expected, actual);
assert_eq!(expected.to_string(), "AA{a}");
}
#[test]
fn parse_part_of_string() {
let mut s = "{a}cb0i16";
let expected = EncodingBox::Struct("a".into(), vec![]);
let actual = EncodingBox::from_start_of_str(&mut s).unwrap();
assert_eq!(expected, actual);
let expected = EncodingBox::Char;
let actual = EncodingBox::from_start_of_str(&mut s).unwrap();
assert_eq!(expected, actual);
let expected = EncodingBox::BitField(16, Some(Box::new((0, EncodingBox::Int))));
let actual = EncodingBox::from_start_of_str(&mut s).unwrap();
assert_eq!(expected, actual);
assert_eq!(s, "");
}
}