use codegen::Scope;
use super::{FragmentGenerator, FragmentGeneratorSpecs};
use crate::generator::{CAP, CAP_GENERIC};
pub struct DropImplGenerator;
impl FragmentGenerator for DropImplGenerator {
fn generate(&self, specs: &FragmentGeneratorSpecs, scope: &mut Scope) {
let record_spec = &specs.record;
let drop_impl = scope
.new_impl(&record_spec.capped_record_name)
.generic(CAP_GENERIC)
.target_generic(CAP)
.impl_trait("Drop");
let drop_fn = drop_impl.new_fn("drop").arg_mut_self();
for datum in &record_spec.data {
drop_fn.line(format!(
"let _{}: {} = unsafe {{ self.data.read({}) }};",
datum.name(),
datum.details().type_name(),
datum.details().offset(),
));
}
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use std::collections::BTreeSet;
use maplit::btreeset;
use pretty_assertions::assert_eq;
use super::*;
use crate::{
generator::{config::GeneratorConfig, generate_variant, tests::assert_fragment_eq},
record::{
definition::builder::native::NativeRecordDefinitionBuilder,
type_resolver::HostTypeResolver,
},
};
#[test]
fn should_generate_empty_drop_impl() {
let mut builder = NativeRecordDefinitionBuilder::new(HostTypeResolver);
builder.close_record_variant();
let definition = builder.build();
let config =
GeneratorConfig::new([Box::new(DropImplGenerator) as Box<dyn FragmentGenerator>]);
let mut scope = Scope::new();
let mut type_size_assertions = BTreeSet::new();
generate_variant(
&definition,
definition.max_type_align(),
definition.variants().next().expect("variant"),
None,
&config,
&mut scope,
&mut type_size_assertions,
);
assert_fragment_eq(
r#"
impl<const CAP: usize> Drop for CappedRecord0<CAP> {
fn drop(&mut self) {
}
}
"#,
&scope.to_string(),
);
assert_eq!(btreeset![], type_size_assertions);
}
#[test]
fn should_generate_drop_impl_with_data() {
let mut builder = NativeRecordDefinitionBuilder::new(HostTypeResolver);
builder.add_datum_allow_uninit::<u32, _>("integer").unwrap();
builder.add_datum::<u32, _>("not_copy_integer").unwrap();
builder.close_record_variant();
let definition = builder.build();
let config =
GeneratorConfig::new([Box::new(DropImplGenerator) as Box<dyn FragmentGenerator>]);
let mut scope = Scope::new();
let mut type_size_assertions = BTreeSet::new();
generate_variant(
&definition,
definition.max_type_align(),
definition.variants().next().expect("variant"),
None,
&config,
&mut scope,
&mut type_size_assertions,
);
assert_fragment_eq(
r#"
impl<const CAP: usize> Drop for CappedRecord0<CAP> {
fn drop(&mut self) {
let _integer: u32 = unsafe { self.data.read(0) };
let _not_copy_integer: u32 = unsafe { self.data.read(4) };
}
}
"#,
&scope.to_string(),
);
assert_eq!(
btreeset![("u32", std::mem::size_of::<u32>())],
type_size_assertions
);
}
#[test]
fn should_generate_next_drop_impl_with_data() {
let mut builder = NativeRecordDefinitionBuilder::new(HostTypeResolver);
let i0 = builder
.add_datum_allow_uninit::<u32, _>("integer0")
.unwrap();
let nci0 = builder.add_datum::<u32, _>("not_copy_integer0").unwrap();
builder
.add_datum_allow_uninit::<bool, _>("boolean1")
.unwrap();
builder.close_record_variant();
builder.remove_datum(i0).unwrap();
builder.remove_datum(nci0).unwrap();
builder
.add_datum_allow_uninit::<u32, _>("integer1")
.unwrap();
builder.add_datum::<u32, _>("not_copy_integer1").unwrap();
builder.close_record_variant();
let definition = builder.build();
let config =
GeneratorConfig::new([Box::new(DropImplGenerator) as Box<dyn FragmentGenerator>]);
let mut scope = Scope::new();
let mut type_size_assertions = BTreeSet::new();
let record0_spec = generate_variant(
&definition,
definition.max_type_align(),
definition.variants().next().expect("variant"),
None,
&config,
&mut scope,
&mut type_size_assertions,
);
let mut scope = Scope::new();
type_size_assertions.clear();
generate_variant(
&definition,
definition.max_type_align(),
definition.variants().nth(1).expect("variant"),
Some(&record0_spec),
&config,
&mut scope,
&mut type_size_assertions,
);
assert_fragment_eq(
r#"
impl<const CAP: usize> Drop for CappedRecord1<CAP> {
fn drop(&mut self) {
let _boolean1: bool = unsafe { self.data.read(8) };
let _integer1: u32 = unsafe { self.data.read(0) };
let _not_copy_integer1: u32 = unsafe { self.data.read(4) };
}
}
"#,
&scope.to_string(),
);
assert_eq!(
btreeset![("u32", std::mem::size_of::<u32>())],
type_size_assertions
);
}
}