1#![allow(dead_code)]
5use std::ops::{Deref, DerefMut};
6
7#[macro_export]
8macro_rules! numerical_enum {
9 (
10 $(#[$attr:meta])*
11 pub enum $enum_name:ident as $repr:tt {
12 $(
13 $(#[$id_attr:meta])*
14 $identifier:ident = $value:literal,
15 )+
16 }
17 ) => {
18 $(#[$attr])*
19 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
20 #[repr($repr)]
21 pub enum $enum_name {
22 $(
23 $(#[$id_attr])*
24 $identifier = $value,
25 )+
26 }
27
28 impl TryFrom<$repr> for $enum_name {
29 type Error = $crate::error::Qcow2Error;
30 fn try_from(val: $repr) -> $crate::error::Qcow2Result<Self> {
31 match val {
32 $($value => Ok($enum_name::$identifier),)*
33 _ => Err($crate::error::Qcow2Error::from_desc(format!(
34 "Invalid value for {}: {:x}",
35 stringify!($enum_name),
36 val
37 ))),
38 }
39 }
40 }
41 }
42}
43
44pub trait IntAlignment: Sized {
46 fn align_down<T: Into<Self>>(self, alignment: T) -> Option<Self>;
50
51 fn align_up<T: Into<Self>>(self, alignment: T) -> Option<Self>;
55}
56
57macro_rules! impl_int_alignment_for_primitive {
58 ($type:tt) => {
59 impl IntAlignment for $type {
60 fn align_down<T: Into<Self>>(self, alignment: T) -> Option<Self> {
61 let alignment: Self = alignment.into();
62 debug_assert!(alignment.is_power_of_two());
63
64 Some(self & !(alignment - 1))
65 }
66
67 fn align_up<T: Into<Self>>(self, alignment: T) -> Option<Self> {
68 let alignment: Self = alignment.into();
69 debug_assert!(alignment.is_power_of_two());
70
71 if self & (alignment - 1) == 0 {
72 return Some(self);
73 }
74 (self | (alignment - 1)).checked_add(1)
75 }
76 }
77 };
78}
79
80impl_int_alignment_for_primitive!(u8);
81impl_int_alignment_for_primitive!(u16);
82impl_int_alignment_for_primitive!(u32);
83impl_int_alignment_for_primitive!(u64);
84impl_int_alignment_for_primitive!(usize);
85
86pub struct Qcow2IoBuf<T> {
89 ptr: *mut T,
90 size: usize,
91}
92
93unsafe impl<T> Send for Qcow2IoBuf<T> {}
95unsafe impl<T> Sync for Qcow2IoBuf<T> {}
96
97impl<T> Qcow2IoBuf<T> {
98 pub fn new(size: usize) -> Self {
99 let layout = std::alloc::Layout::from_size_align(size, 4096).unwrap();
100 let ptr = unsafe { std::alloc::alloc(layout) } as *mut T;
101
102 assert!(size != 0);
103
104 Qcow2IoBuf { ptr, size }
105 }
106
107 #[allow(clippy::len_without_is_empty)]
109 pub fn len(&self) -> usize {
110 let elem_size = core::mem::size_of::<T>();
111 self.size / elem_size
112 }
113
114 pub fn as_ptr(&self) -> *const T {
116 self.ptr
117 }
118
119 pub fn as_mut_ptr(&self) -> *mut T {
121 self.ptr
122 }
123
124 pub(crate) fn as_u8_slice(&self) -> &[u8] {
126 unsafe { std::slice::from_raw_parts(self.ptr as *const u8, self.size) }
127 }
128
129 pub(crate) fn as_u8_slice_mut(&mut self) -> &mut [u8] {
131 unsafe { std::slice::from_raw_parts_mut(self.ptr as *mut u8, self.size) }
132 }
133
134 pub fn zero_buf(&mut self) {
136 unsafe {
137 std::ptr::write_bytes(self.as_mut_ptr(), 0, self.len());
138 }
139 }
140}
141
142impl<T> std::fmt::Debug for Qcow2IoBuf<T> {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 write!(
145 f,
146 "ptr {:?} size {} element type {}",
147 self.ptr,
148 self.size,
149 qcow2_type_of(unsafe { &*self.ptr })
150 )
151 }
152}
153
154impl<T> Deref for Qcow2IoBuf<T> {
156 type Target = [T];
157 fn deref(&self) -> &[T] {
158 let elem_size = core::mem::size_of::<T>();
159 unsafe { std::slice::from_raw_parts(self.ptr, self.size / elem_size) }
160 }
161}
162
163impl<T> DerefMut for Qcow2IoBuf<T> {
165 fn deref_mut(&mut self) -> &mut [T] {
166 let elem_size = core::mem::size_of::<T>();
167 unsafe { std::slice::from_raw_parts_mut(self.ptr, self.size / elem_size) }
168 }
169}
170
171impl<T> Drop for Qcow2IoBuf<T> {
173 fn drop(&mut self) {
174 let layout = std::alloc::Layout::from_size_align(self.size, 4096).unwrap();
175 unsafe { std::alloc::dealloc(self.ptr as *mut u8, layout) };
176 }
177}
178
179pub fn slice_to_vec<T>(s: &[T]) -> Vec<T> {
181 let ptr = s.as_ptr();
183 let len = s.len();
184
185 unsafe { Vec::from_raw_parts(ptr as *mut T, len, len) }
186}
187
188#[macro_export]
189macro_rules! zero_buf {
190 ($buffer:expr) => {{
191 unsafe {
192 std::ptr::write_bytes($buffer.as_mut_ptr(), 0, $buffer.len());
193 }
194 }};
195}
196
197pub fn qcow2_type_of<T>(_: &T) -> String {
198 std::any::type_name::<T>().to_string()
199}