use std::sync::Arc;
use crate::{
metadata::{
streams::Blob,
tables::{CodedIndex, CodedIndexType, ConstantRc, TableInfoRef, TableRow},
token::Token,
typesystem::{CilPrimitive, CilTypeReference},
},
Result,
};
use super::owned::Constant;
#[derive(Clone, Debug)]
pub struct ConstantRaw {
pub rid: u32,
pub token: Token,
pub offset: usize,
pub base: u8,
pub parent: CodedIndex,
pub value: u32,
}
impl ConstantRaw {
pub fn apply<F>(&self, get_ref: F, blob: &Blob) -> Result<()>
where
F: Fn(&CodedIndex) -> CilTypeReference,
{
let parent = get_ref(&self.parent);
let default = CilPrimitive::from_blob(self.base, blob.get(self.value as usize)?)?;
match &parent {
CilTypeReference::Field(field) => {
if !field.signature.base.accepts_constant(&default) {
return Err(malformed_error!(
"Constant type {:?} is not compatible with field type: {:?} (token: {})",
default.kind,
field.signature.base,
self.token.value()
));
}
field
.default
.set(default)
.map_err(|_| malformed_error!("Default value already set for field"))
}
CilTypeReference::Param(param) => {
if let Some(param_type) = param.base.get() {
if let Some(param_type_strong) = param_type.upgrade() {
if !param_type_strong.accepts_constant(&default) {
return Err(malformed_error!(
"Constant type {:?} is not compatible with parameter type {} (token: {})",
default.kind,
param_type_strong.fullname(),
self.token.value()
));
}
}
}
param
.default
.set(default)
.map_err(|_| malformed_error!("Default value already set for param"))
}
CilTypeReference::Property(property) => {
if !property.signature.base.accepts_constant(&default) {
return Err(malformed_error!(
"Constant type {:?} is not compatible with property type: {:?} (token: {})",
default.kind,
property.signature.base,
self.token.value()
));
}
property
.default
.set(default)
.map_err(|_| malformed_error!("Default value already set for property"))
}
_ => Err(malformed_error!(
"Invalid parent type for constant - {}",
self.parent.token.value()
)),
}
}
pub fn to_owned<F>(&self, get_ref: F, blob: &Blob) -> Result<ConstantRc>
where
F: Fn(&CodedIndex) -> CilTypeReference,
{
let parent = get_ref(&self.parent);
if matches!(parent, CilTypeReference::None) {
return Err(malformed_error!(
"Failed to resolve parent token - {}",
self.parent.token.value()
));
}
Ok(Arc::new(Constant {
rid: self.rid,
token: self.token,
offset: self.offset,
c_type: self.base,
parent,
value: Arc::new(CilPrimitive::from_blob(
self.base,
blob.get(self.value as usize)?,
)?),
}))
}
}
impl TableRow for ConstantRaw {
#[rustfmt::skip]
fn row_size(sizes: &TableInfoRef) -> u32 {
u32::from(
1 +
1 +
sizes.coded_index_bytes(CodedIndexType::HasConstant) +
sizes.blob_bytes()
)
}
}