shape_value/v2/
decimal_obj.rs1use super::heap_header::{HeapHeader, HEAP_KIND_V2_DECIMAL};
32use rust_decimal::Decimal;
33
34#[repr(C)]
37pub struct DecimalObj {
38 pub header: HeapHeader,
39 pub value: Decimal,
40}
41
42impl DecimalObj {
43 pub fn new(value: Decimal) -> *mut Self {
46 let layout = std::alloc::Layout::new::<Self>();
47 let ptr = unsafe { std::alloc::alloc(layout) as *mut Self };
48 assert!(!ptr.is_null(), "allocation failed for DecimalObj");
49 unsafe {
50 (*ptr).header = HeapHeader::new(HEAP_KIND_V2_DECIMAL);
51 (*ptr).value = value;
52 }
53 ptr
54 }
55
56 pub unsafe fn value(ptr: *const Self) -> Decimal {
61 unsafe { (*ptr).value }
62 }
63
64 pub unsafe fn drop(ptr: *mut Self) {
70 let layout = std::alloc::Layout::new::<Self>();
72 unsafe { std::alloc::dealloc(ptr as *mut u8, layout) };
73 }
74
75 pub const OFFSET_VALUE: usize = 8;
77}
78
79const _: () = {
85 assert!(std::mem::size_of::<DecimalObj>() == 24);
86 assert!(std::mem::align_of::<DecimalObj>() == 4);
87};
88
89unsafe impl super::heap_element::HeapElement for DecimalObj {
95 unsafe fn release_elem(ptr: *const Self) {
96 if unsafe { super::refcount::v2_release(&(*ptr).header) } {
97 unsafe { Self::drop(ptr as *mut Self) };
98 }
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use rust_decimal::prelude::FromPrimitive;
106
107 #[test]
108 fn test_size_of_decimal_obj() {
109 assert_eq!(std::mem::size_of::<DecimalObj>(), 24);
110 assert_eq!(std::mem::align_of::<DecimalObj>(), 4);
111 }
112
113 #[test]
114 fn test_create_and_read_decimal() {
115 unsafe {
116 let d = Decimal::from_f64(3.14).unwrap();
117 let ptr = DecimalObj::new(d);
118 assert_eq!(DecimalObj::value(ptr), d);
119 assert_eq!((*ptr).header.kind(), HEAP_KIND_V2_DECIMAL);
120 assert_eq!((*ptr).header.get_refcount(), 1);
121 DecimalObj::drop(ptr);
122 }
123 }
124
125 #[test]
126 fn test_create_zero_decimal() {
127 unsafe {
128 let d = Decimal::ZERO;
129 let ptr = DecimalObj::new(d);
130 assert_eq!(DecimalObj::value(ptr), Decimal::ZERO);
131 DecimalObj::drop(ptr);
132 }
133 }
134
135 #[test]
136 fn test_create_max_decimal() {
137 unsafe {
138 let d = Decimal::MAX;
139 let ptr = DecimalObj::new(d);
140 assert_eq!(DecimalObj::value(ptr), Decimal::MAX);
141 DecimalObj::drop(ptr);
142 }
143 }
144
145 #[test]
146 fn test_drop_does_not_leak() {
147 unsafe {
150 for i in 0..200 {
151 let d = Decimal::from_f64(i as f64 * 0.123).unwrap_or(Decimal::ZERO);
152 let ptr = DecimalObj::new(d);
153 DecimalObj::drop(ptr);
154 }
155 }
156 }
157
158 #[test]
159 fn test_field_offsets() {
160 unsafe {
161 let ptr = DecimalObj::new(Decimal::ONE);
162 let base = ptr as usize;
163 let value_offset = &(*ptr).value as *const _ as usize - base;
164 assert_eq!(value_offset, DecimalObj::OFFSET_VALUE, "value must be at offset 8");
165 DecimalObj::drop(ptr);
166 }
167 }
168
169 #[test]
170 fn test_refcount_starts_at_one() {
171 unsafe {
172 let ptr = DecimalObj::new(Decimal::ONE);
173 assert_eq!((*ptr).header.get_refcount(), 1);
174 DecimalObj::drop(ptr);
175 }
176 }
177
178 #[test]
179 fn test_refcount_retain_release() {
180 use crate::v2::refcount::{v2_get_refcount, v2_release, v2_retain};
181 unsafe {
182 let ptr = DecimalObj::new(Decimal::ONE);
183 let header = &(*ptr).header as *const HeapHeader;
184
185 assert_eq!(v2_get_refcount(header), 1);
186 v2_retain(header);
187 assert_eq!(v2_get_refcount(header), 2);
188 assert!(!v2_release(header)); assert_eq!(v2_get_refcount(header), 1);
190
191 DecimalObj::drop(ptr);
193 }
194 }
195
196 #[test]
197 fn test_heap_element_release_elem_to_zero() {
198 use crate::v2::heap_element::HeapElement;
199 unsafe {
200 let ptr = DecimalObj::new(Decimal::ONE);
202 DecimalObj::release_elem(ptr);
203 }
206 }
207
208 #[test]
209 fn test_heap_element_release_elem_held_share() {
210 use crate::v2::heap_element::HeapElement;
211 use crate::v2::refcount::{v2_get_refcount, v2_retain};
212 unsafe {
213 let ptr = DecimalObj::new(Decimal::ONE);
214 let header = &(*ptr).header as *const HeapHeader;
215
216 v2_retain(header); DecimalObj::release_elem(ptr); assert_eq!(v2_get_refcount(header), 1);
219
220 DecimalObj::drop(ptr);
222 }
223 }
224}