Skip to main content

vk/
construction.rs

1//! Host-only construction contracts. Raw fields and native calls remain unsafe boundaries.
2use crate::StructureType;
3
4/// A checked host record could not be constructed. No native operation occurred.
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6pub enum ConstructionError {
7	/// A borrowed array exceeds its native count field's integer width.
8	CountOverflow { field: &'static str, count: usize },
9	/// Parallel arrays do not have the same native count.
10	LengthMismatch {
11		field: &'static str,
12		expected: usize,
13		actual: usize,
14	},
15	/// A single-node insertion received an already-linked node.
16	AlreadyLinked,
17	/// A public native header no longer has its canonical structure tag.
18	UnexpectedStructureType {
19		expected: StructureType,
20		actual: StructureType,
21	},
22}
23
24impl std::fmt::Display for ConstructionError {
25	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26		match self {
27			Self::CountOverflow { field, count } => {
28				write!(f, "Vulkan {field} count {count} exceeds its native width")
29			}
30			Self::LengthMismatch {
31				field,
32				expected,
33				actual,
34			} => write!(f, "Vulkan {field} length {actual}, expected {expected}"),
35			Self::AlreadyLinked => f.write_str("Vulkan extension node already has a p_next link"),
36			Self::UnexpectedStructureType { expected, actual } => {
37				write!(f, "Vulkan structure tag {actual:?}, expected {expected:?}")
38			}
39		}
40	}
41}
42
43impl std::error::Error for ConstructionError {}
44
45pub(crate) fn count(field: &'static str, count: usize) -> Result<u32, ConstructionError> {
46	count_as(field, count)
47}
48
49pub(crate) fn count_as<T: TryFrom<usize>>(
50	field: &'static str,
51	count: usize,
52) -> Result<T, ConstructionError> {
53	T::try_from(count).map_err(|_| ConstructionError::CountOverflow { field, count })
54}
55
56/// A registry-declared extension relationship. Implementations are sealed.
57///
58/// This proves a native chain type relationship, not enabled features, valid raw
59/// pointers, tag uniqueness or GPU resource lifetimes.
60pub trait Extends<Root>: sealed::ChainNode {}
61
62pub(crate) mod sealed {
63	pub trait ChainNode {
64		const S_TYPE: crate::StructureType;
65		fn s_type(&self) -> crate::StructureType;
66		fn p_next(&self) -> *const std::ffi::c_void;
67		fn set_p_next(&mut self, p_next: *mut std::ffi::c_void);
68		fn address(&mut self) -> *mut std::ffi::c_void;
69	}
70}
71
72pub(crate) fn prepend<R: sealed::ChainNode, N: Extends<R>>(
73	root: &mut R,
74	next: &mut N,
75) -> Result<(), ConstructionError> {
76	for (expected, actual) in [(R::S_TYPE, root.s_type()), (N::S_TYPE, next.s_type())] {
77		if actual != expected {
78			return Err(ConstructionError::UnexpectedStructureType { expected, actual });
79		}
80	}
81	if !next.p_next().is_null() {
82		return Err(ConstructionError::AlreadyLinked);
83	}
84	next.set_p_next(root.p_next().cast_mut());
85	root.set_p_next(next.address());
86	Ok(())
87}
88
89#[cfg(test)]
90#[path = "../../test/rs/test_construction_count.rs"]
91mod tests;