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 ¬_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