artichoke_backend/convert/
boolean.rs1use crate::Artichoke;
2use crate::convert::UnboxRubyError;
3use crate::core::{Convert, TryConvert, Value as _};
4use crate::error::Error;
5use crate::sys;
6use crate::types::{Ruby, Rust};
7use crate::value::Value;
8
9impl Convert<bool, Value> for Artichoke {
10 fn convert(&self, value: bool) -> Value {
11 if value {
14 Value::from(unsafe { sys::mrb_sys_true_value() })
15 } else {
16 Value::from(unsafe { sys::mrb_sys_false_value() })
17 }
18 }
19}
20
21impl Convert<Option<bool>, Value> for Artichoke {
22 fn convert(&self, value: Option<bool>) -> Value {
23 let Some(value) = value else {
24 return Value::nil();
25 };
26 self.convert(value)
27 }
28}
29
30impl TryConvert<Value, bool> for Artichoke {
31 type Error = Error;
32
33 fn try_convert(&self, value: Value) -> Result<bool, Self::Error> {
34 let Ruby::Bool = value.ruby_type() else {
35 return Err(UnboxRubyError::new(&value, Rust::Bool).into());
36 };
37 let inner = value.inner();
38 if sys::mrb_sys_value_is_true(inner) {
39 Ok(true)
40 } else if sys::mrb_sys_value_is_false(inner) {
41 Ok(false)
42 } else {
43 Err(UnboxRubyError::new(&value, Rust::Bool).into())
46 }
47 }
48}
49
50impl TryConvert<Value, Option<bool>> for Artichoke {
51 type Error = Error;
52
53 fn try_convert(&self, value: Value) -> Result<Option<bool>, Self::Error> {
54 if value.is_nil() {
55 Ok(None)
56 } else {
57 Ok(Some(self.try_convert(value)?))
58 }
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use crate::test::prelude::*;
65
66 #[test]
67 fn fail_convert() {
68 let mut interp = interpreter();
69 let value = interp.eval(b"Object.new").unwrap();
71 let result = value.try_convert_into::<bool>(&interp);
72 assert!(result.is_err());
73 }
74
75 #[test]
76 fn prop_convert_to_bool() {
77 let interp = interpreter();
78 for b in [true, false] {
79 let value = interp.convert(b);
80 assert_eq!(value.ruby_type(), Ruby::Bool);
81 }
82 }
83
84 #[test]
85 fn prop_convert_to_nilable_bool() {
86 let interp = interpreter();
87 for b in [Some(true), Some(false), None] {
88 let value = interp.convert(b);
89 if b.is_some() {
90 assert_eq!(value.ruby_type(), Ruby::Bool);
91 } else {
92 assert_eq!(value.ruby_type(), Ruby::Nil);
93 }
94 }
95 }
96
97 #[test]
98 fn test_bool_true_with_value() {
99 let interp = interpreter();
100 let value = interp.convert(true);
101 let inner = value.inner();
102 assert!(!sys::mrb_sys_value_is_false(inner));
104 assert!(sys::mrb_sys_value_is_true(inner));
105 assert!(!sys::mrb_sys_value_is_nil(inner));
106 }
107
108 #[test]
109 fn test_bool_false_with_value() {
110 let interp = interpreter();
111 let value = interp.convert(false);
112 let inner = value.inner();
113 assert!(sys::mrb_sys_value_is_false(inner));
115 assert!(!sys::mrb_sys_value_is_true(inner));
116 assert!(!sys::mrb_sys_value_is_nil(inner));
117 }
118
119 #[test]
120 fn test_convert_some_true() {
121 let interp = interpreter();
122 let value = interp.convert(Some(true));
123 let inner = value.inner();
124 assert!(!sys::mrb_sys_value_is_false(inner));
126 assert!(sys::mrb_sys_value_is_true(inner));
127 assert!(!sys::mrb_sys_value_is_nil(inner));
128 }
129
130 #[test]
131 fn test_convert_some_false() {
132 let interp = interpreter();
133 let value = interp.convert(Some(false));
134 let inner = value.inner();
135 assert!(sys::mrb_sys_value_is_false(inner));
137 assert!(!sys::mrb_sys_value_is_true(inner));
138 assert!(!sys::mrb_sys_value_is_nil(inner));
139 }
140
141 #[test]
142 fn test_convert_none() {
143 let interp = interpreter();
144 let value = interp.convert(None::<bool>);
145 let inner = value.inner();
146 assert!(!sys::mrb_sys_value_is_false(inner));
148 assert!(!sys::mrb_sys_value_is_true(inner));
149 assert!(sys::mrb_sys_value_is_nil(inner));
150 }
151
152 #[test]
153 fn prop_roundtrip() {
154 let interp = interpreter();
155 for b in [true, false] {
156 let value = interp.convert(b);
157 let roundtrip: bool = value.try_convert_into(&interp).unwrap();
158 assert_eq!(roundtrip, b);
159 }
160 }
161
162 #[test]
163 fn prop_nilable_roundtrip() {
164 let interp = interpreter();
165 for b in [Some(true), Some(false), None] {
166 let value = interp.convert(b);
167 let roundtrip: Option<bool> = value.try_convert_into(&interp).unwrap();
168 assert_eq!(roundtrip, b);
169 }
170 }
171
172 #[test]
173 fn prop_roundtrip_err() {
174 let interp = interpreter();
175 run_arbitrary::<i64>(|i_val| {
176 let value = interp.convert(i_val);
177 let result: Result<bool, _> = value.try_convert_into(&interp);
178 assert!(result.is_err());
179 });
180 }
181}