use std::fmt::Write as _;
use crate::GcRef;
use crate::descriptor::{BuiltinTypeId, FormatSink, Tracer, TypeDescriptor};
#[repr(C)]
pub struct ClosurePayload {
pub fn_ptr: *const u8,
pub env: Vec<GcRef>,
}
unsafe fn closure_trace(payload: *mut u8, tracer: &mut dyn Tracer) {
let p = unsafe { &*(payload as *const ClosurePayload) };
for captured in p.env.iter() {
tracer.trace(*captured);
}
}
unsafe fn closure_drop(payload: *mut u8) {
unsafe { std::ptr::drop_in_place(payload as *mut ClosurePayload) };
}
unsafe fn closure_format(payload: *const u8, out: &mut FormatSink<'_>) {
let p = unsafe { &*(payload as *const ClosurePayload) };
let _ = write!(out, "<closure:{}>", p.env.len());
}
pub static CLOSURE: TypeDescriptor = TypeDescriptor::builtin::<ClosurePayload>(
BuiltinTypeId::Closure,
"Closure",
closure_trace,
closure_drop,
closure_format,
None,
None,
None,
)
.with_owned_bytes(closure_owned_bytes);
unsafe fn closure_owned_bytes(payload: *const u8) -> usize {
let p = unsafe { &*(payload as *const ClosurePayload) };
p.env.capacity() * std::mem::size_of::<GcRef>()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn closure_descriptor_reports_capabilities() {
assert!(!CLOSURE.is_equatable());
assert!(!CLOSURE.is_hashable());
assert_eq!(CLOSURE.name, "Closure");
assert_eq!(CLOSURE.as_builtin(), Some(BuiltinTypeId::Closure));
}
}