1use enumflags2::{bitflags, BitFlag, BitFlags, FromBitsError};
2use serde::{
3 de::{self, Deserializer, Visitor},
4 ser::{SerializeSeq, Serializer},
5 Deserialize, Serialize,
6};
7use std::{convert::Infallible, fmt, str::FromStr};
8use zvariant::{Signature, Type};
9
10#[bitflags]
13#[non_exhaustive]
14#[repr(u64)]
15#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Default)]
16#[serde(rename_all = "kebab-case")]
17pub enum State {
18 #[default]
20 Invalid,
21 Active,
32 Armed,
34 Busy,
38 Checked,
40 Collapsed,
42 Defunct,
45 Editable,
47 Enabled,
54 Expandable,
57 Expanded,
59 Focusable,
63 Focused,
65 HasTooltip,
67 Horizontal,
69 Iconified,
72 Modal,
75 MultiLine,
78 Multiselectable,
82 Opaque,
86 Pressed,
88 Resizable,
90 Selectable,
94 Selected,
98 Sensitive,
109 Showing,
114 SingleLine,
117 Stale,
122 Transient,
124 Vertical,
128 Visible,
138 ManagesDescendants,
149 Indeterminate,
162 Required,
166 Truncated,
169 Animated,
178 InvalidEntry,
182 SupportsAutocompletion,
193 SelectableText,
200 IsDefault,
205 Visited,
209 Checkable,
212 HasPopup,
218 ReadOnly,
222}
223
224impl State {
225 #[must_use]
231 pub fn to_static_str(&self) -> &'static str {
232 match self {
233 State::Invalid => "invalid",
234 State::Active => "active",
235 State::Armed => "armed",
236 State::Busy => "busy",
237 State::Checked => "checked",
238 State::Collapsed => "collapsed",
239 State::Defunct => "defunct",
240 State::Editable => "editable",
241 State::Enabled => "enabled",
242 State::Expandable => "expandable",
243 State::Expanded => "expanded",
244 State::Focusable => "focusable",
245 State::Focused => "focused",
246 State::HasTooltip => "has-tooltip",
247 State::Horizontal => "horizontal",
248 State::Iconified => "iconified",
249 State::Modal => "modal",
250 State::MultiLine => "multi-line",
251 State::Multiselectable => "multiselectable",
252 State::Opaque => "opaque",
253 State::Pressed => "pressed",
254 State::Resizable => "resizable",
255 State::Selectable => "selectable",
256 State::Selected => "selected",
257 State::Sensitive => "sensitive",
258 State::Showing => "showing",
259 State::SingleLine => "single-line",
260 State::Stale => "stale",
261 State::Transient => "transient",
262 State::Vertical => "vertical",
263 State::Visible => "visible",
264 State::ManagesDescendants => "manages-descendants",
265 State::Indeterminate => "indeterminate",
266 State::Required => "required",
267 State::Truncated => "truncated",
268 State::Animated => "animated",
269 State::InvalidEntry => "invalid-entry",
270 State::SupportsAutocompletion => "supports-autocompletion",
271 State::SelectableText => "selectable-text",
272 State::IsDefault => "is-default",
273 State::Visited => "visited",
274 State::Checkable => "checkable",
275 State::HasPopup => "has-popup",
276 State::ReadOnly => "read-only",
277 }
278 }
279}
280
281impl fmt::Display for State {
282 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
283 f.write_str(self.to_static_str())
284 }
285}
286
287impl From<String> for State {
288 fn from(string: String) -> State {
289 (&*string).into()
290 }
291}
292
293impl FromStr for State {
294 type Err = Infallible;
295 fn from_str(s: &str) -> Result<Self, Self::Err> {
296 Ok(s.into())
297 }
298}
299
300impl From<&str> for State {
301 fn from(string: &str) -> State {
302 match string {
303 "active" => State::Active,
304 "armed" => State::Armed,
305 "busy" => State::Busy,
306 "checked" => State::Checked,
307 "collapsed" => State::Collapsed,
308 "defunct" => State::Defunct,
309 "editable" => State::Editable,
310 "enabled" => State::Enabled,
311 "expandable" => State::Expandable,
312 "expanded" => State::Expanded,
313 "focusable" => State::Focusable,
314 "focused" => State::Focused,
315 "has-tooltip" => State::HasTooltip,
316 "horizontal" => State::Horizontal,
317 "iconified" => State::Iconified,
318 "modal" => State::Modal,
319 "multi-line" => State::MultiLine,
320 "multiselectable" => State::Multiselectable,
321 "opaque" => State::Opaque,
322 "pressed" => State::Pressed,
323 "resizable" => State::Resizable,
324 "selectable" => State::Selectable,
325 "selected" => State::Selected,
326 "sensitive" => State::Sensitive,
327 "showing" => State::Showing,
328 "single-line" => State::SingleLine,
329 "stale" => State::Stale,
330 "transient" => State::Transient,
331 "vertical" => State::Vertical,
332 "visible" => State::Visible,
333 "manages-descendants" => State::ManagesDescendants,
334 "indeterminate" => State::Indeterminate,
335 "required" => State::Required,
336 "truncated" => State::Truncated,
337 "animated" => State::Animated,
338 "invalid-entry" => State::InvalidEntry,
339 "supports-autocompletion" => State::SupportsAutocompletion,
340 "selectable-text" => State::SelectableText,
341 "is-default" => State::IsDefault,
342 "visited" => State::Visited,
343 "checkable" => State::Checkable,
344 "has-popup" => State::HasPopup,
345 "read-only" => State::ReadOnly,
346 _ => State::Invalid,
347 }
348 }
349}
350
351#[allow(clippy::module_name_repetitions)]
352#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
353pub struct StateSet(BitFlags<State>);
355
356impl StateSet {
357 pub fn new<B: Into<BitFlags<State>>>(value: B) -> Self {
369 Self(value.into())
370 }
371
372 pub fn from_bits(bits: u64) -> Result<StateSet, FromBitsError<State>> {
376 Ok(StateSet(BitFlags::from_bits(bits)?))
377 }
378
379 #[must_use]
380 pub fn empty() -> StateSet {
382 StateSet(State::empty())
383 }
384
385 #[must_use]
386 pub fn bits(&self) -> u64 {
388 self.0.bits()
389 }
390
391 pub fn contains<B: Into<BitFlags<State>>>(self, other: B) -> bool {
393 self.0.contains(other)
394 }
395
396 pub fn remove<B: Into<BitFlags<State>>>(&mut self, other: B) {
398 self.0.remove(other);
399 }
400
401 pub fn insert<B: Into<BitFlags<State>>>(&mut self, other: B) {
403 self.0.insert(other);
404 }
405
406 #[must_use]
408 pub fn iter(self) -> enumflags2::Iter<State> {
409 self.0.iter()
410 }
411
412 #[must_use]
413 pub fn is_empty(self) -> bool {
415 self.0.is_empty()
416 }
417
418 pub fn intersects<B: Into<BitFlags<State>>>(self, other: B) -> bool {
420 self.0.intersects(other)
421 }
422
423 pub fn toggle<B: Into<BitFlags<State>>>(&mut self, other: B) {
425 self.0.toggle(other);
426 }
427}
428
429impl IntoIterator for StateSet {
430 type IntoIter = enumflags2::Iter<State>;
431 type Item = State;
432
433 fn into_iter(self) -> Self::IntoIter {
434 self.iter()
435 }
436}
437
438impl IntoIterator for &StateSet {
439 type IntoIter = enumflags2::Iter<State>;
440 type Item = State;
441
442 fn into_iter(self) -> Self::IntoIter {
443 self.iter()
444 }
445}
446
447impl FromIterator<State> for StateSet {
448 fn from_iter<I: IntoIterator<Item = State>>(iter: I) -> Self {
449 StateSet(iter.into_iter().collect())
450 }
451}
452
453impl<'a> FromIterator<&'a State> for StateSet {
454 fn from_iter<I: IntoIterator<Item = &'a State>>(iter: I) -> Self {
455 StateSet(iter.into_iter().copied().collect())
456 }
457}
458
459impl<'de> Deserialize<'de> for StateSet {
460 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
461 where
462 D: Deserializer<'de>,
463 {
464 struct StateSetVisitor;
465
466 impl<'de> Visitor<'de> for StateSetVisitor {
467 type Value = StateSet;
468
469 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
470 formatter
471 .write_str("a sequence comprised of two u32 that represents a valid StateSet")
472 }
473
474 fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
475 where
476 D: Deserializer<'de>,
477 {
478 match <Vec<u32> as Deserialize>::deserialize(deserializer) {
479 Ok(states) if states.len() == 2 => {
480 let mut bits = u64::from(states[0]);
481 bits |= (u64::from(states[1])) << 32;
482 StateSet::from_bits(bits).map_err(|_| de::Error::custom("invalid state"))
483 }
484 Ok(states) => Err(de::Error::invalid_length(states.len(), &"array of size 2")),
485 Err(e) => Err(e),
486 }
487 }
488 }
489
490 deserializer.deserialize_newtype_struct("StateSet", StateSetVisitor)
491 }
492}
493
494impl Serialize for StateSet {
495 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
496 where
497 S: Serializer,
498 {
499 let mut seq = serializer.serialize_seq(Some(2))?;
500 let bits = self.bits();
501
502 #[allow(clippy::cast_possible_truncation)]
505 seq.serialize_element(&(bits as u32))?;
506 seq.serialize_element(&((bits >> 32) as u32))?;
507 seq.end()
508 }
509}
510
511impl Type for StateSet {
512 const SIGNATURE: &'static Signature = <Vec<u32> as Type>::SIGNATURE;
513}
514
515impl From<State> for StateSet {
516 fn from(value: State) -> Self {
517 Self(value.into())
518 }
519}
520
521impl std::ops::BitXor for StateSet {
522 type Output = StateSet;
523
524 fn bitxor(self, other: Self) -> Self::Output {
525 StateSet(self.0 ^ other.0)
526 }
527}
528impl std::ops::BitXorAssign for StateSet {
529 fn bitxor_assign(&mut self, other: Self) {
530 self.0 = self.0 ^ other.0;
531 }
532}
533impl std::ops::BitOr for StateSet {
534 type Output = StateSet;
535
536 fn bitor(self, other: Self) -> Self::Output {
537 StateSet(self.0 | other.0)
538 }
539}
540impl std::ops::BitOrAssign for StateSet {
541 fn bitor_assign(&mut self, other: Self) {
542 self.0 = self.0 | other.0;
543 }
544}
545impl std::ops::BitAnd for StateSet {
546 type Output = StateSet;
547
548 fn bitand(self, other: Self) -> Self::Output {
549 StateSet(self.0 & other.0)
550 }
551}
552impl std::ops::BitAndAssign for StateSet {
553 fn bitand_assign(&mut self, other: Self) {
554 self.0 = self.0 & other.0;
555 }
556}
557
558#[cfg(test)]
559mod tests {
560 use super::{State, StateSet};
561 use zvariant::serialized::{Context, Data};
562 use zvariant::{to_bytes, LE};
563
564 #[test]
565 fn serialize_empty_state_set() {
566 let ctxt = Context::new_dbus(LE, 0);
567 let encoded = to_bytes(ctxt, &StateSet::empty()).unwrap();
568 assert_eq!(encoded.bytes(), &[8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
569 }
570
571 #[test]
572 fn deserialize_empty_state_set() {
573 let ctxt = Context::new_dbus(LE, 0);
574 let data = Data::new::<&[u8]>(&[8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ctxt);
575 let (decoded, _) = data.deserialize::<StateSet>().unwrap();
576 assert_eq!(decoded, StateSet::empty());
577 }
578
579 #[test]
580 fn serialize_state_set_invalid() {
581 let ctxt = Context::new_dbus(LE, 0);
582 let encoded = to_bytes(ctxt, &StateSet::new(State::Invalid)).unwrap();
583 assert_eq!(encoded.bytes(), &[8, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]);
584 }
585
586 #[test]
587 fn deserialize_state_set_invalid() {
588 let ctxt = Context::new_dbus(LE, 0);
589 let data = Data::new::<&[u8]>(&[8, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], ctxt);
590 let (decoded, _) = data.deserialize::<StateSet>().unwrap();
591 assert_eq!(decoded, StateSet::new(State::Invalid));
592 }
593
594 #[test]
595 fn serialize_state_set_manages_descendants() {
596 let ctxt = Context::new_dbus(LE, 0);
597 let encoded = to_bytes(ctxt, &StateSet::new(State::ManagesDescendants)).unwrap();
598 assert_eq!(encoded.bytes(), &[8, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0]);
599 }
600
601 #[test]
602 fn deserialize_state_set_manages_descendants() {
603 let ctxt = Context::new_dbus(LE, 0);
604 let data = Data::new::<&[u8]>(&[8, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0], ctxt);
605 let (decoded, _) = data.deserialize::<StateSet>().unwrap();
606 assert_eq!(decoded, StateSet::new(State::ManagesDescendants));
607 }
608
609 #[test]
610 fn serialize_state_set_indeterminate() {
611 let ctxt = Context::new_dbus(LE, 0);
612 let encoded = to_bytes(ctxt, &StateSet::new(State::Indeterminate)).unwrap();
613 assert_eq!(encoded.bytes(), &[8, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]);
614 }
615
616 #[test]
617 fn deserialize_state_set_indeterminate() {
618 let ctxt = Context::new_dbus(LE, 0);
619 let data = Data::new::<&[u8]>(&[8, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0], ctxt);
620 let (decoded, _) = data.deserialize::<StateSet>().unwrap();
621 assert_eq!(decoded, StateSet::new(State::Indeterminate));
622 }
623
624 #[test]
625 fn serialize_state_set_focusable_focused() {
626 let ctxt = Context::new_dbus(LE, 0);
627 let encoded = to_bytes(ctxt, &StateSet::new(State::Focusable | State::Focused)).unwrap();
628 assert_eq!(encoded.bytes(), &[8, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0]);
629 }
630
631 #[test]
632 fn deserialize_state_set_focusable_focused() {
633 let ctxt = Context::new_dbus(LE, 0);
634 let data = Data::new::<&[u8]>(&[8, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0], ctxt);
635 let (decoded, _) = data.deserialize::<StateSet>().unwrap();
636 assert_eq!(decoded, StateSet::new(State::Focusable | State::Focused));
637 }
638
639 #[test]
640 fn cannot_deserialize_state_set_invalid_length() {
641 let ctxt = Context::new_dbus(LE, 0);
642 let data = Data::new::<&[u8]>(&[4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ctxt);
643 let decode_result = data.deserialize::<StateSet>();
644 assert!(decode_result.is_err());
645 }
646
647 #[test]
648 fn cannot_deserialize_state_set_invalid_flag() {
649 let ctxt = Context::new_dbus(LE, 0);
650 let data = Data::new::<&[u8]>(&[8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32], ctxt);
651 let decode_result = data.deserialize::<StateSet>();
652 assert!(decode_result.is_err());
653 }
654
655 #[test]
656 fn convert_state_direct_string() {
657 for state in
658 StateSet::from_bits(0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111).unwrap()
659 {
660 let state_str: String = state.to_string();
661 let state_two: State = state_str.clone().into();
662 assert_eq!(
663 state, state_two,
664 "The {state:?} was serialized as {state_str}, which deserializes to {state_two:?}"
665 );
666 }
667 }
668 #[test]
669 fn convert_state_direct_string_is_equal_to_serde_output() {
670 for state in
671 StateSet::from_bits(0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111).unwrap()
672 {
673 let serde_state_str: String = serde_plain::to_string(&state).unwrap();
674 let state_str: String = state.to_string();
675 assert_eq!(serde_state_str, state_str);
676 let state_two: State = serde_plain::from_str(&state_str).unwrap();
677 assert_eq!(state, state_two, "The {state:?} was serialized as {state_str}, which deserializes to {state_two:?} (serde)");
678 }
679 }
680
681 #[test]
682 fn collect_stateset_from_owned_states() {
683 let states = vec![State::Active, State::Focused, State::Focusable];
684 let set = StateSet::from_iter(states);
685 assert!(set.contains(State::Active));
686 assert!(set.contains(State::Focused));
687 assert!(set.contains(State::Focusable));
688 }
689
690 #[test]
691 fn collect_stateset_from_borrowed_states() {
692 let states = &[State::Active, State::Focused, State::Focusable];
694 let set = states.iter().collect::<StateSet>();
695 assert!(set.contains(State::Active));
696 assert!(set.contains(State::Focused));
697 assert!(set.contains(State::Focusable));
698 }
699
700 #[test]
701 fn into_iterator_owned_stateset() {
702 let set = StateSet::new(State::Active | State::Focused | State::Focusable);
703 let states: Vec<State> = set.into_iter().collect();
704 assert_eq!(states.len(), 3);
705 assert!(states.contains(&State::Active));
706 assert!(states.contains(&State::Focused));
707 assert!(states.contains(&State::Focusable));
708 }
709
710 #[test]
711 fn into_iterator_borrowed_stateset() {
712 let set = StateSet::new(State::Active | State::Focused | State::Focusable);
713 let states: Vec<State> = (&set).into_iter().collect();
714 assert_eq!(states.len(), 3);
715 assert!(states.contains(&State::Active));
716 assert!(states.contains(&State::Focused));
717 assert!(states.contains(&State::Focusable));
718 }
719}