1use crate::StructureType;
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6pub enum ConstructionError {
7 CountOverflow { field: &'static str, count: usize },
9 LengthMismatch {
11 field: &'static str,
12 expected: usize,
13 actual: usize,
14 },
15 AlreadyLinked,
17 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
56pub 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;