Skip to main content

ohos_arkui_binding/common/
attribute.rs

1//! Module common::attribute wrappers and related types.
2
3use std::ffi::{CStr, CString};
4use std::os::raw::c_void;
5
6use ohos_arkui_sys::{ArkUI_AttributeItem, ArkUI_NumberValue};
7
8#[derive(Debug, Clone, Copy, PartialEq)]
9/// Numeric value used in ArkUI attribute arrays.
10pub enum ArkUINodeAttributeNumber {
11    /// 32-bit float.
12    Float(f32),
13    /// 32-bit signed integer.
14    Int(i32),
15    /// 32-bit unsigned integer.
16    Uint(u32),
17}
18
19/// Generic attribute payload accepted by ArkUI node attribute APIs.
20pub enum ArkUINodeAttributeItem {
21    /// Numeric array payload.
22    NumberValue(Vec<ArkUINodeAttributeNumber>),
23    /// String payload.
24    /// `value` and `size` are set to null and zero in native struct.
25    String(String),
26    /// Opaque object pointer payload.
27    /// `value`, `size` and `string` are empty in native struct.
28    Object(*mut ::std::os::raw::c_void),
29    /// Composite payload for attributes that accept numbers, string, and object together.
30    Composite(ArkUINodeCompositeAttributeItem),
31}
32
33#[derive(Debug, Clone, Default)]
34/// Composite ArkUI attribute payload.
35pub struct ArkUINodeCompositeAttributeItem {
36    pub number_values: Vec<ArkUINodeAttributeNumber>,
37    pub string: Option<String>,
38    pub object: Option<*mut c_void>,
39}
40
41impl ArkUINodeCompositeAttributeItem {
42    pub fn new() -> Self {
43        Self::default()
44    }
45
46    pub fn with_number_values(mut self, value: Vec<ArkUINodeAttributeNumber>) -> Self {
47        self.number_values = value;
48        self
49    }
50
51    pub fn with_string<T: Into<String>>(mut self, value: T) -> Self {
52        self.string = Some(value.into());
53        self
54    }
55
56    pub fn with_object(mut self, value: *mut c_void) -> Self {
57        self.object = Some(value);
58        self
59    }
60}
61
62impl From<ArkUINodeAttributeNumber> for ArkUINodeAttributeItem {
63    fn from(value: ArkUINodeAttributeNumber) -> Self {
64        Self::NumberValue(vec![value])
65    }
66}
67
68impl From<Vec<ArkUINodeAttributeNumber>> for ArkUINodeAttributeItem {
69    fn from(value: Vec<ArkUINodeAttributeNumber>) -> Self {
70        Self::NumberValue(value)
71    }
72}
73
74impl From<f32> for ArkUINodeAttributeItem {
75    fn from(value: f32) -> Self {
76        Self::NumberValue(vec![ArkUINodeAttributeNumber::Float(value)])
77    }
78}
79
80impl From<i32> for ArkUINodeAttributeItem {
81    fn from(value: i32) -> Self {
82        Self::NumberValue(vec![ArkUINodeAttributeNumber::Int(value)])
83    }
84}
85
86impl From<u32> for ArkUINodeAttributeItem {
87    fn from(value: u32) -> Self {
88        Self::NumberValue(vec![ArkUINodeAttributeNumber::Uint(value)])
89    }
90}
91
92impl From<bool> for ArkUINodeAttributeItem {
93    fn from(value: bool) -> Self {
94        Self::NumberValue(vec![ArkUINodeAttributeNumber::Int(if value {
95            1
96        } else {
97            0
98        })])
99    }
100}
101
102impl From<Vec<f32>> for ArkUINodeAttributeItem {
103    fn from(value: Vec<f32>) -> Self {
104        Self::NumberValue(
105            value
106                .into_iter()
107                .map(ArkUINodeAttributeNumber::Float)
108                .collect(),
109        )
110    }
111}
112
113impl From<Vec<i32>> for ArkUINodeAttributeItem {
114    fn from(value: Vec<i32>) -> Self {
115        Self::NumberValue(
116            value
117                .into_iter()
118                .map(ArkUINodeAttributeNumber::Int)
119                .collect(),
120        )
121    }
122}
123
124impl From<Vec<u32>> for ArkUINodeAttributeItem {
125    fn from(value: Vec<u32>) -> Self {
126        Self::NumberValue(
127            value
128                .into_iter()
129                .map(ArkUINodeAttributeNumber::Uint)
130                .collect(),
131        )
132    }
133}
134
135impl From<&str> for ArkUINodeAttributeItem {
136    fn from(value: &str) -> Self {
137        Self::String(value.to_string())
138    }
139}
140
141impl From<String> for ArkUINodeAttributeItem {
142    fn from(value: String) -> Self {
143        Self::String(value)
144    }
145}
146
147impl From<*mut ::std::os::raw::c_void> for ArkUINodeAttributeItem {
148    fn from(value: *mut ::std::os::raw::c_void) -> Self {
149        Self::Object(value)
150    }
151}
152
153impl From<ArkUINodeCompositeAttributeItem> for ArkUINodeAttributeItem {
154    fn from(value: ArkUINodeCompositeAttributeItem) -> Self {
155        Self::Composite(value)
156    }
157}
158
159impl From<&ArkUINodeCompositeAttributeItem> for ArkUINodeAttributeItem {
160    fn from(value: &ArkUINodeCompositeAttributeItem) -> Self {
161        Self::Composite(value.clone())
162    }
163}
164
165macro_rules! impl_from_object_wrapper {
166    ($(#[$meta:meta])* $wrapper:ty) => {
167        $(#[$meta])*
168        impl From<&$wrapper> for ArkUINodeAttributeItem {
169            fn from(value: &$wrapper) -> Self {
170                Self::Object(value.raw().cast())
171            }
172        }
173    };
174}
175
176impl_from_object_wrapper!(crate::LayoutConstraint);
177impl_from_object_wrapper!(crate::AlignmentRuleOption);
178impl_from_object_wrapper!(crate::AccessibilityValue);
179impl_from_object_wrapper!(crate::WaterFlowSectionOption);
180#[cfg(feature = "image")]
181impl_from_object_wrapper!(crate::DrawableDescriptor);
182impl_from_object_wrapper!(crate::SwiperIndicator);
183impl_from_object_wrapper!(crate::ImageAnimatorFrameInfo);
184impl_from_object_wrapper!(crate::ListItemSwipeActionItem);
185impl_from_object_wrapper!(crate::ListItemSwipeActionOption);
186impl_from_object_wrapper!(crate::ListChildrenMainSize);
187impl_from_object_wrapper!(crate::AccessibilityState);
188impl_from_object_wrapper!(crate::GuidelineOption);
189impl_from_object_wrapper!(crate::BarrierOption);
190#[cfg(feature = "drawing")]
191impl_from_object_wrapper!(crate::StyledString);
192impl_from_object_wrapper!(crate::NodeAdapter);
193impl_from_object_wrapper!(crate::TransitionEffect);
194
195#[cfg(feature = "api-15")]
196impl_from_object_wrapper!(crate::ProgressLinearStyleOption);
197#[cfg(feature = "api-17")]
198impl_from_object_wrapper!(crate::VisibleAreaEventOptions);
199#[cfg(feature = "api-19")]
200impl_from_object_wrapper!(crate::SwiperDigitIndicator);
201#[cfg(feature = "api-19")]
202impl_from_object_wrapper!(crate::SwiperArrowStyle);
203#[cfg(feature = "api-19")]
204impl_from_object_wrapper!(crate::TextPickerRangeContentArray);
205#[cfg(feature = "api-19")]
206impl_from_object_wrapper!(crate::TextCascadePickerRangeContentArray);
207#[cfg(feature = "api-20")]
208impl_from_object_wrapper!(crate::EmbeddedComponentOption);
209#[cfg(feature = "api-21")]
210impl_from_object_wrapper!(crate::PositionEdges);
211#[cfg(feature = "api-21")]
212impl_from_object_wrapper!(crate::PixelRoundPolicy);
213#[cfg(feature = "api-21")]
214impl_from_object_wrapper!(crate::ContentTransitionEffect);
215#[cfg(feature = "api-22")]
216impl_from_object_wrapper!(crate::GridLayoutOptions);
217#[cfg(feature = "api-22")]
218impl_from_object_wrapper!(crate::ShowCounterConfig);
219#[cfg(feature = "api-22")]
220impl_from_object_wrapper!(crate::TextEditMenuOptions);
221#[cfg(feature = "api-22")]
222impl_from_object_wrapper!(crate::TextSelectionMenuOptions);
223#[cfg(all(feature = "api-22", feature = "drawing"))]
224impl_from_object_wrapper!(crate::TextLayoutManager);
225
226impl From<ArkUINodeAttributeItem> for ArkUI_AttributeItem {
227    fn from(value: ArkUINodeAttributeItem) -> Self {
228        match value {
229            ArkUINodeAttributeItem::NumberValue(value) => {
230                composite_to_raw(ArkUINodeCompositeAttributeItem::new().with_number_values(value))
231            }
232            ArkUINodeAttributeItem::Object(obj) => {
233                composite_to_raw(ArkUINodeCompositeAttributeItem::new().with_object(obj))
234            }
235            ArkUINodeAttributeItem::String(s) => {
236                composite_to_raw(ArkUINodeCompositeAttributeItem::new().with_string(s))
237            }
238            ArkUINodeAttributeItem::Composite(value) => composite_to_raw(value),
239        }
240    }
241}
242
243impl TryFrom<ArkUI_AttributeItem> for ArkUINodeAttributeItem {
244    type Error = &'static str;
245
246    fn try_from(item: ArkUI_AttributeItem) -> Result<Self, Self::Error> {
247        unsafe {
248            let has_string = !item.string.is_null();
249            let has_object = !item.object.is_null();
250            let has_number_values = !item.value.is_null() && item.size > 0;
251
252            if !(has_string || has_object || has_number_values) {
253                return Err("Invalid ArkUI_AttributeItem - all fields are null");
254            }
255
256            let string = has_string.then(|| {
257                let c_str = CStr::from_ptr(item.string);
258                c_str.to_string_lossy().into_owned()
259            });
260            let object = has_object.then_some(item.object);
261            let number_values = if has_number_values {
262                let slice = std::slice::from_raw_parts(item.value, item.size as usize);
263                slice.iter().map(number_value_from_raw).collect()
264            } else {
265                Vec::new()
266            };
267
268            match (has_number_values, has_string, has_object) {
269                (true, false, false) => Ok(ArkUINodeAttributeItem::NumberValue(number_values)),
270                (false, true, false) => Ok(ArkUINodeAttributeItem::String(
271                    string.expect("string should exist"),
272                )),
273                (false, false, true) => Ok(ArkUINodeAttributeItem::Object(
274                    object.expect("object should exist"),
275                )),
276                _ => Ok(ArkUINodeAttributeItem::Composite(
277                    ArkUINodeCompositeAttributeItem {
278                        number_values,
279                        string,
280                        object,
281                    },
282                )),
283            }
284        }
285    }
286}
287
288impl TryFrom<*const ArkUI_AttributeItem> for ArkUINodeAttributeItem {
289    type Error = &'static str;
290
291    fn try_from(ptr: *const ArkUI_AttributeItem) -> Result<Self, Self::Error> {
292        unsafe {
293            if ptr.is_null() {
294                Err("Null pointer provided")
295            } else {
296                // Dereference the pointer and convert
297                ArkUINodeAttributeItem::try_from(*ptr)
298            }
299        }
300    }
301}
302
303fn composite_to_raw(value: ArkUINodeCompositeAttributeItem) -> ArkUI_AttributeItem {
304    let mut number_values: Vec<ArkUI_NumberValue> =
305        value.number_values.iter().map(raw_number_value).collect();
306    let value_ptr = if number_values.is_empty() {
307        std::ptr::null_mut()
308    } else {
309        let ptr = number_values.as_mut_ptr();
310        std::mem::forget(number_values);
311        ptr
312    };
313    let string_ptr = value
314        .string
315        .map(|string| CString::new(string).unwrap().into_raw())
316        .unwrap_or(std::ptr::null_mut());
317
318    ArkUI_AttributeItem {
319        value: value_ptr,
320        size: value.number_values.len() as i32,
321        string: string_ptr,
322        object: value.object.unwrap_or(std::ptr::null_mut()),
323    }
324}
325
326fn raw_number_value(value: &ArkUINodeAttributeNumber) -> ArkUI_NumberValue {
327    match value {
328        ArkUINodeAttributeNumber::Float(f) => ArkUI_NumberValue { f32_: *f },
329        ArkUINodeAttributeNumber::Int(i) => ArkUI_NumberValue { i32_: *i },
330        ArkUINodeAttributeNumber::Uint(u) => ArkUI_NumberValue { u32_: *u },
331    }
332}
333
334fn number_value_from_raw(value: &ArkUI_NumberValue) -> ArkUINodeAttributeNumber {
335    unsafe {
336        if value.f32_ != 0.0 {
337            ArkUINodeAttributeNumber::Float(value.f32_)
338        } else if value.i32_ != 0 {
339            ArkUINodeAttributeNumber::Int(value.i32_)
340        } else {
341            ArkUINodeAttributeNumber::Uint(value.u32_)
342        }
343    }
344}