extendr_api/scalar/
rbool.rs1use crate::scalar::macros::*;
2use crate::*;
3use std::convert::TryFrom;
4
5#[repr(transparent)]
13#[readonly::make]
14pub struct Rbool(pub i32);
15
16impl Rbool {
17 pub fn new(val: i32) -> Self {
18 Rbool(val)
19 }
20
21 pub const fn true_value() -> Rbool {
23 Rbool(1)
24 }
25
26 pub const fn false_value() -> Rbool {
28 Rbool(0)
29 }
30
31 pub const fn na_value() -> Rbool {
33 Rbool(i32::MIN)
34 }
35
36 pub fn is_true(&self) -> bool {
38 self.0 != 0 && !self.is_na()
39 }
40
41 pub fn is_false(&self) -> bool {
43 self.0 == 0 && !self.is_na()
44 }
45
46 #[deprecated(
48 since = "0.10.0",
49 note = "`NA` converts to `true`. Use `bool::try_from()` or `Option::<bool>::from()` instead"
50 )]
51 pub fn to_bool(&self) -> bool {
52 self.0 != 0
53 }
54
55 #[deprecated(since = "0.10.0", note = "Use `Rbool::from()` or `.into()` instead")]
57 pub fn from_bool(val: bool) -> Self {
58 Rbool(val as i32)
59 }
60}
61
62gen_trait_impl!(Rbool, bool, |x: &Rbool| x.0 == i32::MIN, i32::MIN);
63gen_from_primitive!(Rbool, i32);
64gen_partial_ord!(Rbool, bool);
65
66impl From<bool> for Rbool {
67 fn from(v: bool) -> Self {
68 Rbool(i32::from(v))
69 }
70}
71
72impl From<Option<bool>> for Rbool {
73 fn from(v: Option<bool>) -> Self {
74 if let Some(v) = v {
75 Rbool::from(v)
76 } else {
77 Rbool::na()
78 }
79 }
80}
81
82impl From<Rbool> for Option<bool> {
83 fn from(v: Rbool) -> Self {
85 if v.is_na() {
86 None
87 } else {
88 Some(v.is_true())
89 }
90 }
91}
92
93impl TryFrom<Rbool> for bool {
94 type Error = Error;
95
96 fn try_from(v: Rbool) -> Result<Self> {
98 if v.is_na() {
99 Err(Error::MustNotBeNA(v.into()))
100 } else {
101 Ok(v.is_true())
102 }
103 }
104}
105
106impl std::ops::Not for Rbool {
107 type Output = Self;
108
109 fn not(self) -> Self::Output {
110 if self.is_na() {
111 Rbool::na()
112 } else if self.is_true() {
113 Rbool::false_value()
114 } else {
115 Rbool::true_value()
116 }
117 }
118}
119
120impl std::fmt::Debug for Rbool {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 write!(
123 f,
124 "{}",
125 if self.is_na() {
126 "NA_LOGICAL"
127 } else if self.is_true() {
128 "TRUE"
129 } else {
130 "FALSE"
131 }
132 )
133 }
134}
135
136impl TryFrom<&Robj> for Rbool {
137 type Error = Error;
138
139 fn try_from(robj: &Robj) -> Result<Self> {
142 if let Some(v) = robj.as_logical_slice() {
143 match v.len() {
144 0 => Err(Error::ExpectedNonZeroLength(robj.clone())),
145 1 => Ok(v[0]),
146 _ => Err(Error::ExpectedScalar(robj.clone())),
147 }
148 } else {
149 Err(Error::ExpectedLogical(robj.clone()))
150 }
151 }
152}