/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
usecrate::metadata::{checksum_metadata, codes}; usecrate::*; use anyhow::{bail, ensure, Context, Result};
// Read a metadata type, this is pub so that we can test it in the metadata fixture pubfn read_metadata_type(data: &[u8]) -> Result<Type> {
MetadataReader::new(data).read_type()
}
/// Helper struct for read_metadata() struct MetadataReader<'a> { // This points to the initial data we were passed in
initial_data: &'a [u8], // This points to the remaining data to be read
buf: &'a [u8],
}
// Read a top-level metadata item // // This consumes self because MetadataReader is only intended to read a single item. fn read_metadata(mutself) -> Result<Metadata> { let value = self.read_u8()?;
Ok(match value {
codes::NAMESPACE => NamespaceMetadata {
crate_name: self.read_string()?,
name: self.read_string()?,
}
.into(),
codes::UDL_FILE => UdlFile {
module_path: self.read_string()?,
namespace: self.read_string()?,
file_stub: self.read_string()?,
}
.into(),
codes::FUNC => self.read_func()?.into(),
codes::CONSTRUCTOR => self.read_constructor()?.into(),
codes::METHOD => self.read_method()?.into(),
codes::RECORD => self.read_record()?.into(),
codes::ENUM => self.read_enum()?.into(),
codes::INTERFACE => self.read_object(ObjectImpl::Struct)?.into(),
codes::TRAIT_INTERFACE => self.read_object(ObjectImpl::Trait)?.into(),
codes::CALLBACK_TRAIT_INTERFACE => self.read_object(ObjectImpl::CallbackTrait)?.into(),
codes::CALLBACK_INTERFACE => self.read_callback_interface()?.into(),
codes::TRAIT_METHOD => self.read_trait_method()?.into(),
codes::UNIFFI_TRAIT => self.read_uniffi_trait()?.into(),
_ => bail!("Unexpected metadata code: {value:?}"),
})
}
fn read_u8(&mutself) -> Result<u8> { if !self.buf.is_empty() { let value = self.buf[0]; self.buf = &self.buf[1..];
Ok(value)
} else {
bail!("Buffer is empty")
}
}
fn peek_u8(&mutself) -> Result<u8> { if !self.buf.is_empty() {
Ok(self.buf[0])
} else {
bail!("Buffer is empty")
}
}
fn read_u16(&mutself) -> Result<u16> { ifself.buf.len() >= 2 { // read the value as little-endian let value = u16::from_le_bytes([self.buf[0], self.buf[1]]); self.buf = &self.buf[2..];
Ok(value)
} else {
bail!("Not enough data left in buffer to read a u16 value");
}
}
fn read_u32(&mutself) -> Result<u32> { ifself.buf.len() >= 4 { // read the value as little-endian let value = self.buf[0] as u32
+ ((self.buf[1] as u32) << 8)
+ ((self.buf[2] as u32) << 16)
+ ((self.buf[3] as u32) << 24); self.buf = &self.buf[4..];
Ok(value)
} else {
bail!("Not enough data left in buffer to read a u32 value");
}
}
fn read_func(&mutself) -> Result<FnMetadata> { let module_path = self.read_string()?; let name = self.read_string()?; let is_async = self.read_bool()?; let inputs = self.read_inputs()?; let (return_type, throws) = self.read_return_type()?; let docstring = self.read_optional_long_string()?;
Ok(FnMetadata {
module_path,
name,
is_async,
inputs,
return_type,
throws,
docstring,
checksum: self.calc_checksum(),
})
}
fn read_constructor(&mutself) -> Result<ConstructorMetadata> { let module_path = self.read_string()?; let self_name = self.read_string()?; let name = self.read_string()?; let is_async = self.read_bool()?; let inputs = self.read_inputs()?; let (return_type, throws) = self.read_return_type()?; let docstring = self.read_optional_long_string()?;
return_type
.filter(|t| {
matches!(
t, Type::Object { name, imp: ObjectImpl::Struct, .. } if name == &self_name
)
})
.context("Constructor return type must be Self or Arc<Self>")?;
fn read_trait_method(&mutself) -> Result<TraitMethodMetadata> { let module_path = self.read_string()?; let trait_name = self.read_string()?; let index = self.read_u32()?; let name = self.read_string()?; let is_async = self.read_bool()?; let inputs = self.read_inputs()?; let (return_type, throws) = self.read_return_type()?; let docstring = self.read_optional_long_string()?;
Ok(TraitMethodMetadata {
module_path,
trait_name,
index,
name,
is_async,
inputs,
return_type,
throws,
takes_self_by_arc: false, // not emitted by macros
checksum: self.calc_checksum(),
docstring,
})
}
fn read_fields(&mutself) -> Result<Vec<FieldMetadata>> { let len = self.read_u8()?;
(0..len)
.map(|_| { let name = self.read_string()?; let ty = self.read_type()?; let default = self.read_optional_default(&name, &ty)?;
Ok(FieldMetadata {
name,
ty,
default,
docstring: self.read_optional_long_string()?,
})
})
.collect()
}
fn read_inputs(&mutself) -> Result<Vec<FnParamMetadata>> { let len = self.read_u8()?;
(0..len)
.map(|_| { let name = self.read_string()?; let ty = self.read_type()?; let default = self.read_optional_default(&name, &ty)?;
Ok(FnParamMetadata {
name,
ty,
default, // not emitted by macros
by_ref: false,
optional: false,
})
})
.collect()
}
fn calc_checksum(&self) -> Option<u16> { let bytes_read = self.initial_data.len() - self.buf.len(); let metadata_buf = &self.initial_data[..bytes_read];
Some(checksum_metadata(metadata_buf))
}
Ok(match literal_kind {
codes::LIT_STR => {
ensure!(
matches!(ty, Type::String), "field {name} of type {ty:?} can't have a default value of type string"
);
LiteralMetadata::String(self.read_string()?)
}
codes::LIT_INT => { let base10_digits = self.read_string()?; // procmacros emit the type for discriminant values based purely on whether the constant // is positive or negative. let ty = if !base10_digits.is_empty()
&& base10_digits.as_bytes()[0] == b'-'
&& ty == &Type::UInt64
{
&Type::Int64
} else {
ty
};
macro_rules! parse_int {
($ty:ident, $variant:ident) => {
LiteralMetadata::$variant(
base10_digits
.parse::<$ty>()
.with_context(|| {
format!("parsing default for field {name}: {base10_digits}")
})?
.into(),
Radix::Decimal,
ty.to_owned(),
)
};
}
match ty { Type::UInt8 => parse_int!(u8, UInt), Type::Int8 => parse_int!(i8, Int), Type::UInt16 => parse_int!(u16, UInt), Type::Int16 => parse_int!(i16, Int), Type::UInt32 => parse_int!(u32, UInt), Type::Int32 => parse_int!(i32, Int), Type::UInt64 => parse_int!(u64, UInt), Type::Int64 => parse_int!(i64, Int),
_ => {
bail!("field {name} of type {ty:?} can't have a default value of type integer");
}
}
}
codes::LIT_FLOAT => match ty { Type::Float32 | Type::Float64 => {
LiteralMetadata::Float(self.read_string()?, ty.to_owned())
}
_ => {
bail!("field {name} of type {ty:?} can't have a default value of type float");
}
},
codes::LIT_BOOL => LiteralMetadata::Boolean(self.read_bool()?),
codes::LIT_NONE => match ty { Type::Optional { .. } => LiteralMetadata::None,
_ => bail!("field {name} of type {ty:?} can't have a default value of None"),
},
codes::LIT_SOME => match ty { Type::Optional { inner_type, .. } => LiteralMetadata::Some {
inner: Box::new(self.read_default(name, inner_type)?),
},
_ => bail!("field {name} of type {ty:?} can't have a default value of None"),
},
codes::LIT_EMPTY_SEQ => LiteralMetadata::EmptySequence,
_ => bail!("Unexpected literal kind code: {literal_kind:?}"),
})
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet am 2026-06-19)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.