Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #![allow(unused)]
- use byteorder::ByteOrder;
- use std::{error, fmt, str};
- pub const U32_SIGNATURE: char = 'u';
- pub const U32_SIGNATURE_STR: &'static str = "u";
- pub const STRING_SIGNATURE: char = 's';
- pub const STRING_SIGNATURE_STR: &'static str = "s";
- #[derive(Debug)]
- pub enum VariantError {
- IncorrectType,
- InvalidUtf8,
- InsufficientData,
- UnsupportedType,
- }
- impl error::Error for VariantError {
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- None
- }
- }
- impl fmt::Display for VariantError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- VariantError::IncorrectType => write!(f, "incorrect type"),
- VariantError::InvalidUtf8 => write!(f, "invalid UTF-8"),
- VariantError::InsufficientData => write!(f, "insufficient data"),
- VariantError::UnsupportedType => write!(f, "unsupported type"),
- }
- }
- }
- pub trait VariantType<'a>: Sized {
- fn signature() -> char;
- fn signature_str() -> &'static str;
- fn encode(&'a self) -> &'a [u8];
- fn extract_slice(data: &'a [u8]) -> Result<&'a [u8], VariantError>;
- fn extract(bytes: &'a [u8]) -> Result<Self, VariantError>
- where
- Self: 'a;
- }
- impl<'a> VariantType<'a> for u32 {
- fn signature() -> char {
- 'u'
- }
- fn signature_str() -> &'static str {
- "u"
- }
- fn encode(&'a self) -> &'a [u8] {
- &self.to_ne_bytes()
- }
- fn extract_slice(bytes: &'a [u8]) -> Result<&'a [u8], VariantError> {
- if bytes.len() < 4 {
- return Err(VariantError::InsufficientData);
- }
- Ok(&bytes[0..4])
- }
- fn extract(bytes: &'a [u8]) -> Result<Self, VariantError>
- where
- Self: 'a,
- {
- if bytes.len() < 4 {
- return Err(VariantError::InsufficientData);
- }
- Ok(byteorder::NativeEndian::read_u32(bytes))
- }
- }
- impl<'a> VariantType<'a> for &'a str {
- fn signature() -> char {
- 's'
- }
- fn signature_str() -> &'static str {
- "s"
- }
- fn encode(&'a self) -> &'a [u8] {
- let len = self.len();
- let mut bytes = Vec::with_capacity(5 + len);
- bytes.extend(&(len as u32).to_ne_bytes());
- bytes.extend(self.as_bytes());
- bytes.push(b'\0');
- &bytes
- }
- fn extract_slice(bytes: &'a [u8]) -> Result<&'a [u8], VariantError> {
- if bytes.len() < 4 {
- return Err(VariantError::InsufficientData);
- }
- let last_index = byteorder::NativeEndian::read_u32(bytes) as usize + 5;
- if bytes.len() < last_index {
- return Err(VariantError::InsufficientData);
- }
- Ok(&bytes[0..last_index])
- }
- fn extract(bytes: &'a [u8]) -> Result<Self, VariantError>
- where
- Self: 'a,
- {
- if bytes.len() < 4 {
- return Err(VariantError::InsufficientData);
- }
- str::from_utf8(&bytes[4..]).map_err(|_| VariantError::InvalidUtf8)
- }
- }
- pub struct Variant<'a> {
- // FIXME: This should be an `&str`
- signature: String,
- value: &'a [u8],
- }
- impl<'a> Variant<'a> {
- pub fn from_data(data: &'a [u8], signature: &str) -> Result<Self, VariantError>
- where
- Self: 'a,
- {
- let value = match signature {
- // FIXME: There has to be a shorter way to do this
- U32_SIGNATURE_STR => u32::extract_slice(data)?,
- STRING_SIGNATURE_STR => <(&str)>::extract_slice(data)?,
- _ => return Err(VariantError::UnsupportedType),
- };
- Ok(Self {
- value,
- signature: String::from(signature),
- })
- }
- pub fn from<T: 'a + VariantType>(value: T) -> Self
- where
- Self: 'a,
- {
- Self {
- value: value.encode(),
- signature: String::from(T::signature_str()),
- }
- }
- pub fn get_signature(&self) -> &str {
- &self.signature
- }
- pub fn get<T: 'a + VariantType>(&'a self) -> Result<T, VariantError> {
- VariantType::extract(self.value)
- }
- // FIXME: Return a slice
- pub fn get_bytes(&self) -> &[u8] {
- self.value
- }
- pub fn len(&self) -> usize {
- self.value.len()
- }
- }
- fn main() {
- println!("{}", <(&str)>::extract());
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement