ohos_arkui_binding/common/
attribute.rs1use 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)]
9pub enum ArkUINodeAttributeNumber {
11 Float(f32),
13 Int(i32),
15 Uint(u32),
17}
18
19pub enum ArkUINodeAttributeItem {
21 NumberValue(Vec<ArkUINodeAttributeNumber>),
23 String(String),
26 Object(*mut ::std::os::raw::c_void),
29 Composite(ArkUINodeCompositeAttributeItem),
31}
32
33#[derive(Debug, Clone, Default)]
34pub 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 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}