• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #![allow(clippy::unwrap_used)]
16 
17 extern crate std;
18 
19 use crate::{
20     legacy::{
21         data_elements::{
22             actions::{self, *},
23             tests::macros::de_roundtrip_test,
24         },
25         serialize::encode_de_header,
26         serialize::tests::serialize,
27         Ciphertext, Plaintext,
28     },
29     DeLengthOutOfRange,
30 };
31 use rand::seq::SliceRandom;
32 use rand::Rng;
33 use std::collections;
34 use std::panic;
35 use std::prelude::rust_2021::*;
36 
37 #[test]
setting_action_only_changes_that_actions_bits()38 fn setting_action_only_changes_that_actions_bits() {
39     fn do_test<F: PacketFlavor>(
40         set_ones: impl Fn(ActionType, &mut ActionBits<F>),
41         set_zeros: impl Fn(ActionType, &mut ActionBits<F>),
42     ) {
43         for t in supported_action_types(F::ENUM_VARIANT) {
44             let other_types = supported_action_types(F::ENUM_VARIANT)
45                 .into_iter()
46                 .filter(|t2| *t2 != t)
47                 .collect::<Vec<_>>();
48 
49             let mut actions = ActionBits::<F>::default();
50             set_ones(t, &mut actions);
51 
52             // only the correct bits are set internally
53             assert_eq!(t.all_bits(), actions.as_u32());
54             // we can extract those bits
55             assert_eq!(t.all_bits() >> (31 - t.high_bit_index()), actions.bits_for_type(t));
56             // consider context sync (None) to be "set" for our purposes
57             assert!(actions.has_action(t));
58             // other types aren't set
59             for &t2 in &other_types {
60                 assert_eq!(0, actions.bits_for_type(t2))
61             }
62 
63             // now check that unsetting works
64             actions.bits = u32::MAX;
65             set_zeros(t, &mut actions);
66 
67             assert_eq!(!t.all_bits(), actions.as_u32());
68             assert_eq!(0, actions.bits_for_type(t));
69             assert!(!actions.has_action(t));
70             // other types are set
71             for &t2 in &other_types {
72                 assert_eq!(t2.all_bits() >> (31 - t2.high_bit_index()), actions.bits_for_type(t2));
73             }
74         }
75     }
76 
77     do_test(
78         |t, bits| set_plaintext_action(t, true, bits),
79         |t, bits| set_plaintext_action(t, false, bits),
80     );
81     do_test(
82         |t, bits| set_ciphertexttext_action(t, true, bits),
83         |t, bits| set_ciphertexttext_action(t, false, bits),
84     );
85 }
86 
87 #[test]
random_combos_of_actions_have_correct_bits_set()88 fn random_combos_of_actions_have_correct_bits_set() {
89     fn do_test<F: PacketFlavor>(set_ones: impl Fn(ActionType, &mut ActionBits<F>)) {
90         let all_types = supported_action_types(F::ENUM_VARIANT);
91         let mut rng = rand::thread_rng();
92 
93         for _ in 0..1000 {
94             let len = rng.gen_range(0..=all_types.len());
95             let selected = all_types.choose_multiple(&mut rng, len).copied().collect::<Vec<_>>();
96             let not_selected =
97                 all_types.iter().filter(|t| !selected.contains(t)).copied().collect::<Vec<_>>();
98 
99             let mut actions = ActionBits::<F>::default();
100             for &t in &selected {
101                 set_ones(t, &mut actions);
102             }
103 
104             for &t in &selected {
105                 assert_ne!(0, actions.bits_for_type(t));
106             }
107             for &t in &not_selected {
108                 assert_eq!(0, actions.bits_for_type(t));
109             }
110 
111             assert_eq!(selected.iter().fold(0, |accum, t| accum | t.all_bits()), actions.bits);
112         }
113     }
114 
115     do_test::<Plaintext>(|t, bits| set_plaintext_action(t, true, bits));
116     do_test::<Ciphertext>(|t, bits| set_ciphertexttext_action(t, true, bits));
117 }
118 
119 #[test]
set_last_bit_works()120 fn set_last_bit_works() {
121     let mut actions = ActionBits::<Plaintext>::default();
122 
123     actions.set_action(LastBit::from(true));
124     assert_eq_hex(0x0100, actions.bits);
125 }
126 
127 #[test]
set_last_bit_doesnt_clobber_others()128 fn set_last_bit_doesnt_clobber_others() {
129     let mut actions = ActionBits::<Plaintext>::default();
130 
131     // set neighboring bits
132     actions.bits |= 0x200;
133 
134     actions.set_action(LastBit::from(true));
135     assert_eq_hex(0x300, actions.bits);
136 }
137 
138 #[test]
unset_last_bit_works()139 fn unset_last_bit_works() {
140     let mut actions = ActionBits::<Plaintext> {
141         // all 1s
142         bits: u32::MAX,
143         ..Default::default()
144     };
145 
146     actions.set_action(LastBit::from(false));
147     assert_eq_hex(0xFFFFFEFF, actions.bits);
148 }
149 
150 #[test]
bytes_used_works()151 fn bytes_used_works() {
152     let mut actions = ActionBits::<Plaintext>::default();
153 
154     // Special-case: All-zeroes should lead to a single byte being used.
155     assert_eq!(1, actions.bytes_used());
156 
157     actions.set_action(NearbyShare::from(true));
158     assert_eq!(2, actions.bytes_used());
159 
160     actions.set_action(LastBit::from(true));
161     assert_eq!(3, actions.bytes_used());
162 
163     actions.set_action(LastBit::from(false));
164     assert_eq!(2, actions.bytes_used());
165 }
166 
167 #[test]
write_de_empty_actions()168 fn write_de_empty_actions() {
169     // The special case of no action bits set should still occupy one byte [of all zeroes].
170 
171     assert_eq!(
172         &[actions_de_header_byte(1), 0x00],
173         serialize(&ActionsDataElement::<Plaintext>::from(ActionBits::default())).as_slice()
174     );
175 }
176 
177 #[test]
write_de_one_action_byte()178 fn write_de_one_action_byte() {
179     let mut action = ActionBits::default();
180     action.set_action(FirstBit::from(true));
181 
182     assert_eq!(
183         &[actions_de_header_byte(1), 0b1000_0000],
184         serialize(&ActionsDataElement::<Plaintext>::from(action)).as_slice()
185     );
186 }
187 
188 #[test]
write_de_three_action_bytes()189 fn write_de_three_action_bytes() {
190     let mut action = ActionBits::default();
191     action.set_action(LastBit::from(true));
192 
193     assert_eq!(
194         &[actions_de_header_byte(3), 0, 0, 1],
195         serialize(&ActionsDataElement::<Plaintext>::from(action)).as_slice()
196     );
197 }
198 
199 #[test]
write_de_all_plaintext_actions()200 fn write_de_all_plaintext_actions() {
201     let mut action = all_plaintext_actions_set();
202     action.set_action(LastBit::from(true));
203 
204     // byte 0: cross dev sdk = 1
205     // byte 1: nearby share
206     // byte 2: last bit
207     assert_eq!(
208         &[actions_de_header_byte(3), 0x40, 0x40, 0x01],
209         serialize(&ActionsDataElement::<Plaintext>::from(action)).as_slice()
210     );
211 }
212 
213 #[test]
write_de_all_encrypted_actions()214 fn write_de_all_encrypted_actions() {
215     let mut action = all_ciphertext_actions_set();
216     action.set_action(LastBit::from(true));
217 
218     // byte 1: cross dev sdk = 1, call transfer = 4
219     // byte 2: active unlock, nearby share, instant tethering, phone hub,
220     // byte 3: last bit
221     assert_eq!(
222         &[actions_de_header_byte(3), 0x48, 0xF0, 0x01],
223         serialize(&ActionsDataElement::<Ciphertext>::from(action)).as_slice()
224     );
225 }
226 
227 #[test]
roundtrip_de_random_action_combos()228 fn roundtrip_de_random_action_combos() {
229     fn do_test<F>(set_ones: impl Fn(ActionType, &mut ActionBits<F>))
230     where
231         F: PacketFlavor,
232         ActionsDataElement<F>: DeserializeDataElement,
233     {
234         let all_types = supported_action_types(F::ENUM_VARIANT);
235         let mut rng = rand::thread_rng();
236 
237         for _ in 0..1000 {
238             let len = rng.gen_range(0..=all_types.len());
239             let selected = all_types.choose_multiple(&mut rng, len).copied().collect::<Vec<_>>();
240 
241             let mut actions = ActionBits::<F>::default();
242             for &t in &selected {
243                 set_ones(t, &mut actions);
244             }
245 
246             let de = ActionsDataElement::<F>::from(actions);
247             let serialized = serialize(&de);
248             // skip header
249             let contents = &serialized.as_slice()[1..];
250             let deserialized = ActionsDataElement::<F>::deserialize(contents).unwrap();
251 
252             assert_eq!(de.action, deserialized.action);
253         }
254     }
255 
256     do_test::<Plaintext>(|t, bits| set_plaintext_action(t, true, bits));
257     do_test::<Ciphertext>(|t, bits| set_ciphertexttext_action(t, true, bits));
258 }
259 
260 #[test]
action_element_bits_dont_overlap()261 fn action_element_bits_dont_overlap() {
262     let type_to_bits =
263         ActionType::iter().map(|t| (t, t.all_bits())).collect::<collections::HashMap<_, _>>();
264 
265     for t in ActionType::iter() {
266         let bits = type_to_bits.get(&t).unwrap();
267 
268         for (_, other_bits) in type_to_bits.iter().filter(|(other_type, _)| t != **other_type) {
269             assert_eq!(0, bits & other_bits, "type {t:?}");
270         }
271     }
272 }
273 
274 #[test]
action_type_all_bits_masks()275 fn action_type_all_bits_masks() {
276     assert_eq!(0x08000000, ActionType::CallTransfer.all_bits());
277     assert_eq!(0x00800000, ActionType::ActiveUnlock.all_bits());
278     assert_eq!(0x00400000, ActionType::NearbyShare.all_bits());
279     assert_eq!(0x00200000, ActionType::InstantTethering.all_bits());
280     assert_eq!(0x00100000, ActionType::PhoneHub.all_bits());
281 }
282 
283 #[test]
action_type_all_bits_in_per_type_masks()284 fn action_type_all_bits_in_per_type_masks() {
285     for t in supported_action_types(PacketFlavorEnum::Plaintext) {
286         assert_eq!(t.all_bits(), t.all_bits() & *ALL_PLAINTEXT_ELEMENT_BITS);
287     }
288     for t in supported_action_types(PacketFlavorEnum::Ciphertext) {
289         assert_eq!(t.all_bits(), t.all_bits() & *ALL_CIPHERTEXT_ELEMENT_BITS);
290     }
291 }
292 
293 #[test]
action_bits_try_from_flavor_mismatch_plaintext()294 fn action_bits_try_from_flavor_mismatch_plaintext() {
295     assert_eq!(
296         FlavorNotSupported { flavor: PacketFlavorEnum::Plaintext },
297         ActionBits::<Plaintext>::try_from(ActionType::CallTransfer.all_bits()).unwrap_err()
298     );
299 }
300 
301 #[test]
actions_de_deser_plaintext_with_ciphertext_action()302 fn actions_de_deser_plaintext_with_ciphertext_action() {
303     assert_eq!(
304         DataElementDeserializeError::FlavorNotSupported {
305             de_type: ActionsDataElement::<Plaintext>::DE_TYPE_CODE,
306             flavor: PacketFlavorEnum::Plaintext,
307         },
308         <ActionsDataElement<Plaintext> as DeserializeDataElement>::deserialize::<Plaintext>(&[
309             // active unlock bit set
310             0x00, 0x80, 0x00,
311         ])
312         .unwrap_err()
313     );
314 }
315 
316 #[test]
actions_de_deser_ciphertext_with_plaintext_action()317 fn actions_de_deser_ciphertext_with_plaintext_action() {
318     assert_eq!(
319         DataElementDeserializeError::FlavorNotSupported {
320             de_type: ActionsDataElement::<Plaintext>::DE_TYPE_CODE,
321             flavor: PacketFlavorEnum::Ciphertext,
322         },
323         <ActionsDataElement<Ciphertext> as DeserializeDataElement>::deserialize::<Ciphertext>(&[
324             // Finder bit set
325             0x00, 0x00, 0x80,
326         ])
327         .unwrap_err()
328     );
329 }
330 
331 #[test]
actions_de_deser_plaintext_with_ciphertext_error()332 fn actions_de_deser_plaintext_with_ciphertext_error() {
333     assert_eq!(
334         DataElementDeserializeError::FlavorNotSupported {
335             de_type: ActionsDataElement::<Plaintext>::DE_TYPE_CODE,
336             flavor: PacketFlavorEnum::Plaintext,
337         },
338         <ActionsDataElement<Ciphertext> as DeserializeDataElement>::deserialize::<Plaintext>(&[
339             0x00
340         ])
341         .unwrap_err()
342     );
343 }
344 
345 #[test]
actions_de_deser_ciphertext_with_plaintext_error()346 fn actions_de_deser_ciphertext_with_plaintext_error() {
347     assert_eq!(
348         DataElementDeserializeError::FlavorNotSupported {
349             de_type: ActionsDataElement::<Plaintext>::DE_TYPE_CODE,
350             flavor: PacketFlavorEnum::Ciphertext,
351         },
352         <ActionsDataElement<Plaintext> as DeserializeDataElement>::deserialize::<Ciphertext>(&[
353             0x00
354         ])
355         .unwrap_err()
356     );
357 }
358 
359 #[test]
deserialize_content_too_long_error()360 fn deserialize_content_too_long_error() {
361     assert_eq!(
362         DataElementDeserializeError::DeserializeError {
363             de_type: ActionsDataElement::<Plaintext>::DE_TYPE_CODE
364         },
365         <ActionsDataElement<Plaintext> as DeserializeDataElement>::deserialize::<Plaintext>(
366             &[0x00; 10]
367         )
368         .unwrap_err()
369     );
370 }
371 
372 #[test]
actions_min_len_unencrypted()373 fn actions_min_len_unencrypted() {
374     let actions = ActionBits::<Plaintext>::default();
375 
376     let (_de, ser) = de_roundtrip_test!(
377         ActionsDataElement<Plaintext>,
378         Actions,
379         Actions,
380         Plaintext,
381         serialize(&actions::ActionsDataElement::from(actions))
382     );
383 
384     assert_eq!(
385         &[
386             encode_de_header(
387                 ActionsDataElement::<Plaintext>::DE_TYPE_CODE,
388                 DeEncodedLength::from(1),
389             ),
390             0
391         ],
392         ser.as_slice()
393     );
394 }
395 
396 #[test]
actions_min_len_ldt()397 fn actions_min_len_ldt() {
398     let actions = ActionBits::<Ciphertext>::default();
399 
400     let (_de, ser) = de_roundtrip_test!(
401         ActionsDataElement<Ciphertext>,
402         Actions,
403         Actions,
404         Ciphertext,
405         serialize(&actions::ActionsDataElement::from(actions))
406     );
407 
408     // header and 1 DE contents byte
409     assert_eq!(2, ser.as_slice().len());
410 }
411 
412 #[test]
actions_de_contents_normal_actions_roundtrip_unencrypted()413 fn actions_de_contents_normal_actions_roundtrip_unencrypted() {
414     let actions = all_plaintext_actions_set();
415 
416     let _ = de_roundtrip_test!(
417         ActionsDataElement<Plaintext>,
418         Actions,
419         Actions,
420         Plaintext,
421         serialize(&actions::ActionsDataElement::from(actions))
422     );
423 }
424 
425 #[test]
actions_de_contents_normal_actions_roundtrip_ldt()426 fn actions_de_contents_normal_actions_roundtrip_ldt() {
427     let actions = all_ciphertext_actions_set();
428 
429     let _ = de_roundtrip_test!(
430         ActionsDataElement<Ciphertext>,
431         Actions,
432         Actions,
433         Ciphertext,
434         serialize(&actions::ActionsDataElement::from(actions))
435     );
436 }
437 
438 #[test]
has_action_plaintext_works()439 fn has_action_plaintext_works() {
440     let mut action_bits = ActionBits::<Plaintext>::default();
441     action_bits.set_action(NearbyShare::from(true));
442     let action_de = ActionsDataElement::from(action_bits);
443     assert!(action_de.action.has_action(ActionType::NearbyShare));
444     assert!(!action_de.action.has_action(ActionType::ActiveUnlock));
445     assert!(!action_de.action.has_action(ActionType::PhoneHub));
446 }
447 
448 #[test]
has_action_encrypted_works()449 fn has_action_encrypted_works() {
450     let mut action_bits = ActionBits::<Ciphertext>::default();
451     action_bits.set_action(NearbyShare::from(true));
452     action_bits.set_action(ActiveUnlock::from(true));
453     let action_de = ActionsDataElement::from(action_bits);
454     assert!(action_de.action.has_action(ActionType::NearbyShare));
455     assert!(action_de.action.has_action(ActionType::ActiveUnlock));
456     assert!(!action_de.action.has_action(ActionType::PhoneHub));
457 }
458 
459 #[test]
actual_length_must_be_in_range()460 fn actual_length_must_be_in_range() {
461     let de = ActionsDataElement::<Plaintext>::from(ActionBits::default());
462 
463     for l in [0, ACTIONS_MAX_LEN + 1] {
464         let actual = DeActualLength::try_from(l).unwrap();
465         let _ = panic::catch_unwind(|| de.map_actual_len_to_encoded_len(actual)).unwrap_err();
466     }
467 
468     for l in ACTIONS_VALID_ACTUAL_LEN {
469         assert_eq!(
470             l,
471             de.map_actual_len_to_encoded_len(DeActualLength::try_from(l).unwrap()).as_usize()
472         )
473     }
474 }
475 
476 #[test]
encoded_length_must_be_in_range()477 fn encoded_length_must_be_in_range() {
478     for l in [0, ACTIONS_MAX_LEN + 1] {
479         assert_eq!(
480             DeLengthOutOfRange,
481             <ActionsDataElement<Plaintext> as DeserializeDataElement>::LengthMapper::map_encoded_len_to_actual_len(
482                 DeEncodedLength::try_from(l as u8).unwrap()
483             )
484                 .unwrap_err()
485         )
486     }
487 
488     for l in ACTIONS_VALID_ACTUAL_LEN {
489         assert_eq!(
490             l,
491             <ActionsDataElement<Plaintext> as DeserializeDataElement>::LengthMapper::map_encoded_len_to_actual_len(
492                 DeEncodedLength::try_from(l as u8).unwrap()
493             )
494                 .unwrap()
495                 .as_usize()
496         );
497     }
498 }
499 
500 mod coverage_gaming {
501     use crate::legacy::data_elements::actions::*;
502     use crate::legacy::Plaintext;
503     use alloc::format;
504 
505     #[test]
actions_de_debug()506     fn actions_de_debug() {
507         let actions = ActionsDataElement::<Plaintext>::from(ActionBits::default());
508         let _ = format!("{:?}", actions);
509     }
510 
511     #[test]
flavor_not_supported_debug()512     fn flavor_not_supported_debug() {
513         let _ = format!("{:?}", FlavorNotSupported { flavor: PacketFlavorEnum::Plaintext });
514     }
515 
516     #[test]
action_type_clone_debug()517     fn action_type_clone_debug() {
518         let _ = format!("{:?}", ActionType::CallTransfer.clone());
519     }
520 
521     #[test]
actions_debug()522     fn actions_debug() {
523         let _ = format!("{:?}", CallTransfer::from(true));
524         let _ = format!("{:?}", ActiveUnlock::from(true));
525         let _ = format!("{:?}", NearbyShare::from(true));
526         let _ = format!("{:?}", InstantTethering::from(true));
527         let _ = format!("{:?}", PhoneHub::from(true));
528     }
529 }
530 
531 // Test only action which uses the first bit
532 #[derive(Debug)]
533 pub(crate) struct FirstBit {
534     enabled: bool,
535 }
536 
537 impl From<bool> for FirstBit {
from(value: bool) -> Self538     fn from(value: bool) -> Self {
539         FirstBit { enabled: value }
540     }
541 }
542 
543 impl ActionElement for FirstBit {
544     const HIGH_BIT_INDEX: u32 = 0;
545     // don't want to add a variant for this test only type
546     const ACTION_TYPE: ActionType = ActionType::ActiveUnlock;
547 
supports_flavor(_flavor: PacketFlavorEnum) -> bool548     fn supports_flavor(_flavor: PacketFlavorEnum) -> bool {
549         true
550     }
551 
bits(&self) -> u8552     fn bits(&self) -> u8 {
553         self.enabled as u8
554     }
555 }
556 
557 macros::boolean_element_to_plaintext_element!(FirstBit);
558 macros::boolean_element_to_encrypted_element!(FirstBit);
559 
560 // hypothetical action using the last bit
561 #[derive(Debug)]
562 pub(crate) struct LastBit {
563     enabled: bool,
564 }
565 
566 impl From<bool> for LastBit {
from(value: bool) -> Self567     fn from(value: bool) -> Self {
568         LastBit { enabled: value }
569     }
570 }
571 
572 impl ActionElement for LastBit {
573     const HIGH_BIT_INDEX: u32 = 23;
574     // don't want to add a variant for this test only type
575     const ACTION_TYPE: ActionType = ActionType::ActiveUnlock;
576 
supports_flavor(_flavor: PacketFlavorEnum) -> bool577     fn supports_flavor(_flavor: PacketFlavorEnum) -> bool {
578         true
579     }
580 
bits(&self) -> u8581     fn bits(&self) -> u8 {
582         self.enabled as u8
583     }
584 }
585 
586 macros::boolean_element_to_plaintext_element!(LastBit);
587 macros::boolean_element_to_encrypted_element!(LastBit);
588 
589 // An action that only supports plaintext, to allow testing that error case
590 pub(in crate::legacy) struct PlaintextOnly {
591     enabled: bool,
592 }
593 
594 impl From<bool> for PlaintextOnly {
from(value: bool) -> Self595     fn from(value: bool) -> Self {
596         Self { enabled: value }
597     }
598 }
599 
600 impl ActionElement for PlaintextOnly {
601     const HIGH_BIT_INDEX: u32 = 22;
602 
603     const ACTION_TYPE: ActionType = ActionType::ActiveUnlock;
604 
supports_flavor(flavor: PacketFlavorEnum) -> bool605     fn supports_flavor(flavor: PacketFlavorEnum) -> bool {
606         match flavor {
607             PacketFlavorEnum::Plaintext => true,
608             PacketFlavorEnum::Ciphertext => false,
609         }
610     }
611 
bits(&self) -> u8612     fn bits(&self) -> u8 {
613         self.enabled as u8
614     }
615 }
616 
617 macros::boolean_element_to_plaintext_element!(PlaintextOnly);
618 // sneakily allow serializing it, but deserializing will fail due to supports_flavor above
619 macros::boolean_element_to_encrypted_element!(PlaintextOnly);
620 
assert_eq_hex(expected: u32, actual: u32)621 fn assert_eq_hex(expected: u32, actual: u32) {
622     assert_eq!(expected, actual, "{expected:#010X} != {actual:#010X}");
623 }
624 
all_plaintext_actions_set() -> ActionBits<Plaintext>625 pub(crate) fn all_plaintext_actions_set() -> ActionBits<Plaintext> {
626     let mut action = ActionBits::default();
627     action.set_action(CrossDevSdk::from(true));
628     action.set_action(NearbyShare::from(true));
629 
630     assert!(supported_action_types(PacketFlavorEnum::Plaintext)
631         .into_iter()
632         .all(|t| t.all_bits() & action.bits != 0));
633 
634     action
635 }
636 
all_ciphertext_actions_set() -> ActionBits<Ciphertext>637 pub(crate) fn all_ciphertext_actions_set() -> ActionBits<Ciphertext> {
638     let mut action = ActionBits::default();
639     action.set_action(CrossDevSdk::from(true));
640     action.set_action(CallTransfer::from(true));
641     action.set_action(ActiveUnlock::from(true));
642     action.set_action(NearbyShare::from(true));
643     action.set_action(InstantTethering::from(true));
644     action.set_action(PhoneHub::from(true));
645 
646     assert!(supported_action_types(PacketFlavorEnum::Ciphertext)
647         .into_iter()
648         .all(|t| t.all_bits() & action.bits != 0));
649 
650     action
651 }
652 
supported_action_types(flavor: PacketFlavorEnum) -> Vec<ActionType>653 fn supported_action_types(flavor: PacketFlavorEnum) -> Vec<ActionType> {
654     ActionType::iter().filter(|t| t.supports_flavor(flavor)).collect()
655 }
656 
657 /// Encode a DE header byte with the provided type and actual len, transforming into an encoded
658 /// len appropriately.
actions_de_header_byte(actual_len: u8) -> u8659 fn actions_de_header_byte(actual_len: u8) -> u8 {
660     encode_de_header(
661         ActionsDataElement::<Plaintext>::DE_TYPE_CODE,
662         DeEncodedLength::try_from(actual_len).unwrap(),
663     )
664 }
665 
set_plaintext_action(t: ActionType, value: bool, bits: &mut ActionBits<Plaintext>)666 pub(crate) fn set_plaintext_action(t: ActionType, value: bool, bits: &mut ActionBits<Plaintext>) {
667     match t {
668         ActionType::CrossDevSdk => bits.set_action(CrossDevSdk::from(value)),
669         ActionType::NearbyShare => bits.set_action(NearbyShare::from(value)),
670         ActionType::CallTransfer
671         | ActionType::PhoneHub
672         | ActionType::ActiveUnlock
673         | ActionType::InstantTethering => panic!(),
674     }
675 }
676 
set_ciphertexttext_action( t: ActionType, value: bool, bits: &mut ActionBits<Ciphertext>, )677 pub(crate) fn set_ciphertexttext_action(
678     t: ActionType,
679     value: bool,
680     bits: &mut ActionBits<Ciphertext>,
681 ) {
682     match t {
683         ActionType::CrossDevSdk => bits.set_action(CrossDevSdk::from(value)),
684         ActionType::CallTransfer => bits.set_action(CallTransfer::from(value)),
685         ActionType::ActiveUnlock => bits.set_action(ActiveUnlock::from(value)),
686         ActionType::NearbyShare => bits.set_action(NearbyShare::from(value)),
687         ActionType::InstantTethering => bits.set_action(InstantTethering::from(value)),
688         ActionType::PhoneHub => bits.set_action(PhoneHub::from(value)),
689     }
690 }
691