1use std::ffi::c_void;
2use std::ptr;
3
4#[derive(Clone, Copy, Debug)]
10pub enum Value {
11 Bool(bool),
12 I32(i32),
13 I64(i64),
14 F32(f32),
15 F64(f64),
16 Object(*mut c_void),
18}
19
20impl Value {
21 pub(crate) fn as_arg_ptr(&self) -> *mut c_void {
23 match self {
24 Self::Bool(v) => ptr::from_ref(v).cast_mut().cast(),
25 Self::I32(v) => ptr::from_ref(v).cast_mut().cast(),
26 Self::I64(v) => ptr::from_ref(v).cast_mut().cast(),
27 Self::F32(v) => ptr::from_ref(v).cast_mut().cast(),
28 Self::F64(v) => ptr::from_ref(v).cast_mut().cast(),
29 Self::Object(p) => *p,
30 }
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use std::ffi::c_void;
37
38 use super::Value;
39
40 #[test]
41 fn value_is_copy() {
42 let a = Value::I32(42);
43 let b = a;
44 let _ = a;
46 let _ = b;
47 }
48
49 #[test]
50 fn bool_true_arg_ptr_reads_back() {
51 let v = Value::Bool(true);
52 let read = unsafe { v.as_arg_ptr().cast::<bool>().read() };
53 assert!(read);
54 }
55
56 #[test]
57 fn bool_false_arg_ptr_reads_back() {
58 let v = Value::Bool(false);
59 let read = unsafe { v.as_arg_ptr().cast::<bool>().read() };
60 assert!(!read);
61 }
62
63 #[test]
64 fn i32_arg_ptr_reads_back() {
65 let v = Value::I32(-99_999);
66 let read = unsafe { v.as_arg_ptr().cast::<i32>().read() };
67 assert_eq!(read, -99_999);
68 }
69
70 #[test]
71 fn i64_arg_ptr_reads_back() {
72 let v = Value::I64(i64::MAX);
73 let read = unsafe { v.as_arg_ptr().cast::<i64>().read() };
74 assert_eq!(read, i64::MAX);
75 }
76
77 #[test]
78 fn f32_arg_ptr_reads_back() {
79 let v = Value::F32(1.5_f32);
80 let read = unsafe { v.as_arg_ptr().cast::<f32>().read() };
81 assert!((read - 1.5_f32).abs() < f32::EPSILON);
82 }
83
84 #[test]
85 fn f64_arg_ptr_reads_back() {
86 let v = Value::F64(std::f64::consts::PI);
87 let read = unsafe { v.as_arg_ptr().cast::<f64>().read() };
88 assert!((read - std::f64::consts::PI).abs() < f64::EPSILON);
89 }
90
91 #[test]
92 fn object_arg_ptr_returns_stored_pointer() {
93 let raw: *mut c_void = 0xDEAD_BEEF_usize as *mut _;
94 let v = Value::Object(raw);
95 assert_eq!(v.as_arg_ptr(), raw);
96 }
97
98 #[test]
99 fn object_null_arg_ptr_is_null() {
100 let v = Value::Object(std::ptr::null_mut());
101 assert!(v.as_arg_ptr().is_null());
102 }
103
104 #[test]
105 fn debug_output_includes_variant_names() {
106 assert!(format!("{:?}", Value::Bool(true)).contains("Bool"));
107 assert!(format!("{:?}", Value::I32(0)).contains("I32"));
108 assert!(format!("{:?}", Value::I64(0)).contains("I64"));
109 assert!(format!("{:?}", Value::F32(0.0)).contains("F32"));
110 assert!(format!("{:?}", Value::F64(0.0)).contains("F64"));
111 assert!(format!("{:?}", Value::Object(std::ptr::null_mut())).contains("Object"));
112 }
113}