1use alloc::boxed::Box;
16use alloc::collections::BTreeMap;
17use alloc::string::String;
18use alloc::vec::Vec;
19
20use super::descriptor::{MemberId, TypeKind};
21use super::error::DynamicError;
22use super::type_::DynamicType;
23
24#[derive(Debug, Clone)]
32pub enum DynamicValue {
33 Bool(bool),
35 Byte(u8),
37 Int8(i8),
39 UInt8(u8),
41 Int16(i16),
43 UInt16(u16),
45 Int32(i32),
47 UInt32(u32),
49 Int64(i64),
51 UInt64(u64),
53 Float32(f32),
55 Float64(f64),
57 Char8(u8),
59 Char16(u16),
61 String(String),
63 WString(Vec<u16>),
65 Complex(Box<DynamicData>),
67 Sequence(Vec<DynamicData>),
70 None,
72}
73
74impl PartialEq for DynamicValue {
75 fn eq(&self, other: &Self) -> bool {
76 match (self, other) {
77 (Self::Bool(a), Self::Bool(b)) => a == b,
78 (Self::Byte(a), Self::Byte(b)) => a == b,
79 (Self::Int8(a), Self::Int8(b)) => a == b,
80 (Self::UInt8(a), Self::UInt8(b)) => a == b,
81 (Self::Int16(a), Self::Int16(b)) => a == b,
82 (Self::UInt16(a), Self::UInt16(b)) => a == b,
83 (Self::Int32(a), Self::Int32(b)) => a == b,
84 (Self::UInt32(a), Self::UInt32(b)) => a == b,
85 (Self::Int64(a), Self::Int64(b)) => a == b,
86 (Self::UInt64(a), Self::UInt64(b)) => a == b,
87 (Self::Float32(a), Self::Float32(b)) => a.to_bits() == b.to_bits(),
88 (Self::Float64(a), Self::Float64(b)) => a.to_bits() == b.to_bits(),
89 (Self::Char8(a), Self::Char8(b)) => a == b,
90 (Self::Char16(a), Self::Char16(b)) => a == b,
91 (Self::String(a), Self::String(b)) => a == b,
92 (Self::WString(a), Self::WString(b)) => a == b,
93 (Self::Complex(a), Self::Complex(b)) => a.equals(b),
94 (Self::Sequence(a), Self::Sequence(b)) => {
95 a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.equals(y))
96 }
97 (Self::None, Self::None) => true,
98 _ => false,
99 }
100 }
101}
102
103impl DynamicValue {
104 fn kind_str(&self) -> &'static str {
105 match self {
106 Self::Bool(_) => "bool",
107 Self::Byte(_) => "byte",
108 Self::Int8(_) => "int8",
109 Self::UInt8(_) => "uint8",
110 Self::Int16(_) => "int16",
111 Self::UInt16(_) => "uint16",
112 Self::Int32(_) => "int32",
113 Self::UInt32(_) => "uint32",
114 Self::Int64(_) => "int64",
115 Self::UInt64(_) => "uint64",
116 Self::Float32(_) => "float32",
117 Self::Float64(_) => "float64",
118 Self::Char8(_) => "char8",
119 Self::Char16(_) => "char16",
120 Self::String(_) => "string",
121 Self::WString(_) => "wstring",
122 Self::Complex(_) => "complex",
123 Self::Sequence(_) => "sequence",
124 Self::None => "none",
125 }
126 }
127}
128
129#[derive(Debug)]
138pub struct DataLoan {
139 member_id: MemberId,
140 handle: u32,
142}
143
144impl DataLoan {
145 #[must_use]
147 pub fn member_id(&self) -> MemberId {
148 self.member_id
149 }
150}
151
152#[derive(Debug, Clone)]
163pub struct DynamicData {
164 type_: DynamicType,
165 values: BTreeMap<MemberId, DynamicValue>,
166 active_loans: Vec<u32>,
168 next_loan_handle: u32,
170}
171
172impl DynamicData {
173 pub(super) fn new(type_: DynamicType) -> Self {
174 Self {
175 type_,
176 values: BTreeMap::new(),
177 active_loans: Vec::new(),
178 next_loan_handle: 1,
179 }
180 }
181
182 #[must_use]
184 pub fn dynamic_type(&self) -> &DynamicType {
185 &self.type_
186 }
187
188 #[must_use]
190 pub fn equals(&self, other: &Self) -> bool {
191 self.type_.equals(&other.type_) && self.values == other.values
192 }
193
194 #[must_use]
196 pub fn item_count(&self) -> u32 {
197 u32::try_from(self.values.len()).unwrap_or(u32::MAX)
198 }
199
200 fn validate_member(&self, member_id: MemberId) -> Result<(), DynamicError> {
202 if self.type_.member_by_id(member_id).is_none() {
203 return Err(DynamicError::bad_parameter(alloc::format!(
204 "no member with id {member_id} in type {}",
205 self.type_.name()
206 )));
207 }
208 Ok(())
209 }
210
211 fn set(&mut self, member_id: MemberId, value: DynamicValue) -> Result<(), DynamicError> {
219 self.validate_member(member_id)?;
220 let member = self.type_.member_by_id(member_id).cloned();
221 if let Some(ref m) = member {
222 check_value_kind_matches_type(&value, m.dynamic_type().kind())?;
223 }
224 if let Some(m) = member {
227 match crate::dynamic::try_construct::apply_try_construct(&m, value) {
228 crate::dynamic::TryConstructOutcome::Accept(v)
229 | crate::dynamic::TryConstructOutcome::UseDefault(v)
230 | crate::dynamic::TryConstructOutcome::Trim(v) => {
231 self.values.insert(member_id, v);
232 }
233 crate::dynamic::TryConstructOutcome::Discard => {
234 self.values.remove(&member_id);
236 }
237 }
238 } else {
239 self.values.insert(member_id, value);
240 }
241 Ok(())
242 }
243
244 fn get(&self, member_id: MemberId) -> Result<&DynamicValue, DynamicError> {
246 self.values.get(&member_id).ok_or_else(|| {
247 DynamicError::PreconditionNotMet(alloc::format!(
248 "member {member_id} not set in {}",
249 self.type_.name()
250 ))
251 })
252 }
253
254 #[must_use]
259 pub fn get_value(&self, member_id: MemberId) -> Option<&DynamicValue> {
260 self.values.get(&member_id)
261 }
262
263 pub fn set_value_raw(&mut self, member_id: MemberId, value: DynamicValue) {
268 self.values.insert(member_id, value);
269 }
270
271 #[must_use]
274 pub fn set_member_ids(&self) -> alloc::vec::Vec<MemberId> {
275 let mut ids: alloc::vec::Vec<MemberId> = self.values.keys().copied().collect();
276 ids.sort_by_key(|id| self.type_.member_by_id(*id).map_or(u32::MAX, |m| m.index()));
278 ids
279 }
280}
281
282macro_rules! primitive_accessor {
287 ($get_name:ident, $set_name:ident, $rust_ty:ty, $variant:ident) => {
288 impl DynamicData {
289 #[doc = concat!("Spec §7.5.6.3 `get_", stringify!($variant), "_value`.")]
290 pub fn $get_name(&self, member_id: MemberId) -> Result<$rust_ty, DynamicError> {
295 let v = self.get(member_id)?;
296 if let DynamicValue::$variant(x) = v {
297 Ok(x.clone())
298 } else {
299 Err(DynamicError::bad_parameter(alloc::format!(
300 "type mismatch: expected {} got {}",
301 stringify!($variant),
302 v.kind_str()
303 )))
304 }
305 }
306
307 #[doc = concat!("Spec §7.5.6.3 `set_", stringify!($variant), "_value`.")]
308 pub fn $set_name(
312 &mut self,
313 member_id: MemberId,
314 value: $rust_ty,
315 ) -> Result<(), DynamicError> {
316 self.set(member_id, DynamicValue::$variant(value))
317 }
318 }
319 };
320}
321
322primitive_accessor!(get_boolean_value, set_boolean_value, bool, Bool);
323primitive_accessor!(get_byte_value, set_byte_value, u8, Byte);
324primitive_accessor!(get_int8_value, set_int8_value, i8, Int8);
325primitive_accessor!(get_uint8_value, set_uint8_value, u8, UInt8);
326primitive_accessor!(get_int16_value, set_int16_value, i16, Int16);
327primitive_accessor!(get_uint16_value, set_uint16_value, u16, UInt16);
328primitive_accessor!(get_int32_value, set_int32_value, i32, Int32);
329primitive_accessor!(get_uint32_value, set_uint32_value, u32, UInt32);
330primitive_accessor!(get_int64_value, set_int64_value, i64, Int64);
331primitive_accessor!(get_uint64_value, set_uint64_value, u64, UInt64);
332primitive_accessor!(get_float32_value, set_float32_value, f32, Float32);
333primitive_accessor!(get_float64_value, set_float64_value, f64, Float64);
334primitive_accessor!(get_char8_value, set_char8_value, u8, Char8);
335primitive_accessor!(get_char16_value, set_char16_value, u16, Char16);
336
337impl DynamicData {
339 pub fn get_string_value(&self, member_id: MemberId) -> Result<String, DynamicError> {
344 let v = self.get(member_id)?;
345 if let DynamicValue::String(s) = v {
346 Ok(s.clone())
347 } else {
348 Err(DynamicError::bad_parameter(alloc::format!(
349 "type mismatch: expected string got {}",
350 v.kind_str()
351 )))
352 }
353 }
354
355 pub fn set_string_value(
360 &mut self,
361 member_id: MemberId,
362 value: impl Into<String>,
363 ) -> Result<(), DynamicError> {
364 self.set(member_id, DynamicValue::String(value.into()))
365 }
366
367 pub fn get_wstring_value(&self, member_id: MemberId) -> Result<Vec<u16>, DynamicError> {
372 let v = self.get(member_id)?;
373 if let DynamicValue::WString(s) = v {
374 Ok(s.clone())
375 } else {
376 Err(DynamicError::bad_parameter(alloc::format!(
377 "type mismatch: expected wstring got {}",
378 v.kind_str()
379 )))
380 }
381 }
382
383 pub fn set_wstring_value(
388 &mut self,
389 member_id: MemberId,
390 value: Vec<u16>,
391 ) -> Result<(), DynamicError> {
392 self.set(member_id, DynamicValue::WString(value))
393 }
394}
395
396impl DynamicData {
401 pub fn get_complex_value(&self, member_id: MemberId) -> Result<&DynamicData, DynamicError> {
408 let v = self.get(member_id)?;
409 if let DynamicValue::Complex(d) = v {
410 Ok(d)
411 } else {
412 Err(DynamicError::bad_parameter(alloc::format!(
413 "type mismatch: expected complex got {}",
414 v.kind_str()
415 )))
416 }
417 }
418
419 pub fn set_complex_value(
424 &mut self,
425 member_id: MemberId,
426 value: DynamicData,
427 ) -> Result<(), DynamicError> {
428 self.set(member_id, DynamicValue::Complex(Box::new(value)))
429 }
430
431 pub fn get_sequence_length(&self, member_id: MemberId) -> Result<u32, DynamicError> {
436 let v = self.get(member_id)?;
437 if let DynamicValue::Sequence(seq) = v {
438 Ok(u32::try_from(seq.len()).unwrap_or(u32::MAX))
439 } else {
440 Err(DynamicError::bad_parameter(alloc::format!(
441 "type mismatch: expected sequence got {}",
442 v.kind_str()
443 )))
444 }
445 }
446
447 pub fn set_sequence_value(
452 &mut self,
453 member_id: MemberId,
454 value: Vec<DynamicData>,
455 ) -> Result<(), DynamicError> {
456 self.set(member_id, DynamicValue::Sequence(value))
457 }
458
459 pub fn get_sequence_element(
464 &self,
465 member_id: MemberId,
466 index: u32,
467 ) -> Result<&DynamicData, DynamicError> {
468 let v = self.get(member_id)?;
469 if let DynamicValue::Sequence(seq) = v {
470 seq.get(index as usize).ok_or_else(|| {
471 DynamicError::bad_parameter(alloc::format!(
472 "sequence index {index} out of range (len={})",
473 seq.len()
474 ))
475 })
476 } else {
477 Err(DynamicError::bad_parameter(alloc::format!(
478 "type mismatch: expected sequence got {}",
479 v.kind_str()
480 )))
481 }
482 }
483}
484
485impl DynamicData {
490 pub fn loan_value(&mut self, member_id: MemberId) -> Result<DataLoan, DynamicError> {
499 self.validate_member(member_id)?;
500 if self.active_loans.contains(&member_id) {
501 return Err(DynamicError::loan(alloc::format!(
502 "member {member_id} is already on loan"
503 )));
504 }
505 self.active_loans.push(member_id);
506 let handle = self.next_loan_handle;
507 self.next_loan_handle = self.next_loan_handle.saturating_add(1);
508 Ok(DataLoan { member_id, handle })
509 }
510
511 pub fn return_loaned_value(&mut self, loan: DataLoan) -> Result<(), DynamicError> {
516 let pos = self
517 .active_loans
518 .iter()
519 .position(|m| *m == loan.member_id)
520 .ok_or_else(|| {
521 DynamicError::loan(alloc::format!(
522 "no active loan for member {}",
523 loan.member_id
524 ))
525 })?;
526 self.active_loans.swap_remove(pos);
527 let _ = loan.handle;
530 Ok(())
531 }
532}
533
534fn check_value_kind_matches_type(value: &DynamicValue, kind: TypeKind) -> Result<(), DynamicError> {
536 let ok = match (value, kind) {
537 (DynamicValue::Bool(_), TypeKind::Boolean) => true,
538 (DynamicValue::Byte(_), TypeKind::Byte) => true,
539 (DynamicValue::Int8(_), TypeKind::Int8) => true,
540 (DynamicValue::UInt8(_), TypeKind::UInt8) => true,
541 (DynamicValue::Int16(_), TypeKind::Int16) => true,
542 (DynamicValue::UInt16(_), TypeKind::UInt16) => true,
543 (DynamicValue::Int32(_), TypeKind::Int32 | TypeKind::Enumeration) => true,
544 (DynamicValue::UInt32(_), TypeKind::UInt32) => true,
545 (DynamicValue::Int64(_), TypeKind::Int64) => true,
546 (DynamicValue::UInt64(_), TypeKind::UInt64) => true,
547 (DynamicValue::Float32(_), TypeKind::Float32) => true,
548 (DynamicValue::Float64(_), TypeKind::Float64) => true,
549 (DynamicValue::Char8(_), TypeKind::Char8) => true,
550 (DynamicValue::Char16(_), TypeKind::Char16) => true,
551 (DynamicValue::String(_), TypeKind::String8) => true,
552 (DynamicValue::WString(_), TypeKind::String16) => true,
553 (DynamicValue::Complex(_), k) if k.is_aggregable() => true,
554 (DynamicValue::Sequence(_), TypeKind::Sequence | TypeKind::Array) => true,
555 (DynamicValue::None, _) => true,
556 _ => false,
557 };
558 if !ok {
559 return Err(DynamicError::bad_parameter(alloc::format!(
560 "value kind {} cannot be assigned to member kind {kind:?}",
561 value.kind_str()
562 )));
563 }
564 Ok(())
565}
566
567#[cfg(test)]
568#[allow(clippy::unwrap_used)]
569mod tests {
570 use super::*;
571 use crate::dynamic::DynamicTypeBuilderFactory;
572 use crate::dynamic::descriptor::{MemberDescriptor, TypeDescriptor};
573
574 fn struct_with_int32_member() -> DynamicType {
575 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
576 b.add_struct_member("x", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
577 .unwrap();
578 b.build().unwrap()
579 }
580
581 #[test]
582 fn set_get_int32_roundtrips() {
583 let t = struct_with_int32_member();
584 let mut d = DynamicData::new(t);
585 d.set_int32_value(1, 42).unwrap();
586 assert_eq!(d.get_int32_value(1).unwrap(), 42);
587 }
588
589 #[test]
590 fn set_int32_into_int64_member_rejected() {
591 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
592 b.add_struct_member("x", 1, TypeDescriptor::primitive(TypeKind::Int64, "int64"))
593 .unwrap();
594 let t = b.build().unwrap();
595 let mut d = DynamicData::new(t);
596 let err = d.set_int32_value(1, 5).unwrap_err();
597 assert!(matches!(err, DynamicError::BadParameter(_)));
598 }
599
600 #[test]
601 fn unknown_member_id_rejected() {
602 let t = struct_with_int32_member();
603 let mut d = DynamicData::new(t);
604 let err = d.set_int32_value(999, 0).unwrap_err();
605 assert!(matches!(err, DynamicError::BadParameter(_)));
606 }
607
608 #[test]
609 fn loan_double_rejected() {
610 let t = struct_with_int32_member();
611 let mut d = DynamicData::new(t);
612 let _l = d.loan_value(1).unwrap();
613 let err = d.loan_value(1).unwrap_err();
614 assert!(matches!(err, DynamicError::LoanError(_)));
615 }
616
617 #[test]
618 fn loan_return_then_loan_again_works() {
619 let t = struct_with_int32_member();
620 let mut d = DynamicData::new(t);
621 let l = d.loan_value(1).unwrap();
622 d.return_loaned_value(l).unwrap();
623 let _l2 = d.loan_value(1).unwrap();
624 }
625
626 #[test]
627 fn return_unknown_loan_rejected() {
628 let t = struct_with_int32_member();
629 let mut d = DynamicData::new(t);
630 let fake = DataLoan {
631 member_id: 1,
632 handle: 99,
633 };
634 let err = d.return_loaned_value(fake).unwrap_err();
635 assert!(matches!(err, DynamicError::LoanError(_)));
636 }
637
638 #[test]
639 fn item_count_grows_with_sets() {
640 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
641 b.add_struct_member("a", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
642 .unwrap();
643 b.add_struct_member("b", 2, TypeDescriptor::primitive(TypeKind::Int64, "int64"))
644 .unwrap();
645 let t = b.build().unwrap();
646 let mut d = DynamicData::new(t);
647 assert_eq!(d.item_count(), 0);
648 d.set_int32_value(1, 10).unwrap();
649 assert_eq!(d.item_count(), 1);
650 d.set_int64_value(2, 20).unwrap();
651 assert_eq!(d.item_count(), 2);
652 }
653
654 #[test]
655 fn equals_distinguishes_value_diffs() {
656 let t = struct_with_int32_member();
657 let mut a = DynamicData::new(t.clone());
658 let mut b = DynamicData::new(t);
659 a.set_int32_value(1, 5).unwrap();
660 b.set_int32_value(1, 6).unwrap();
661 assert!(!a.equals(&b));
662 b.set_int32_value(1, 5).unwrap();
663 assert!(a.equals(&b));
664 }
665
666 #[test]
667 fn complex_value_set_get() {
668 let mut inner = DynamicTypeBuilderFactory::create_struct("::Inner");
670 inner
671 .add_struct_member("v", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
672 .unwrap();
673 let inner_t = inner.build().unwrap();
674
675 let mut outer = DynamicTypeBuilderFactory::create_struct("::Outer");
676 outer
677 .add_member(MemberDescriptor::new(
678 "nested",
679 10,
680 TypeDescriptor::structure("::Inner"),
681 ))
682 .unwrap();
683 let outer_t = outer.build().unwrap();
684
685 let mut inner_data = DynamicData::new(inner_t);
686 inner_data.set_int32_value(1, 99).unwrap();
687
688 let mut outer_data = DynamicData::new(outer_t);
689 outer_data.set_complex_value(10, inner_data).unwrap();
690
691 let got = outer_data.get_complex_value(10).unwrap();
692 assert_eq!(got.get_int32_value(1).unwrap(), 99);
693 }
694
695 #[test]
696 fn sequence_length_and_element_access() {
697 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
698 b.add_struct_member(
699 "items",
700 1,
701 TypeDescriptor::sequence(
702 "items",
703 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
704 100,
705 ),
706 )
707 .unwrap();
708 let t = b.build().unwrap();
709
710 let elem_t = DynamicTypeBuilderFactory::get_primitive_type(TypeKind::Int32).unwrap();
711 let mut e0 = DynamicData::new(elem_t.clone());
712 e0.values.insert(0, DynamicValue::Int32(7));
713 let mut e1 = DynamicData::new(elem_t);
714 e1.values.insert(0, DynamicValue::Int32(8));
715 let mut d = DynamicData::new(t);
716 d.set_sequence_value(1, alloc::vec![e0, e1]).unwrap();
717 assert_eq!(d.get_sequence_length(1).unwrap(), 2);
718 let _ = d.get_sequence_element(1, 0).unwrap();
719 assert!(d.get_sequence_element(1, 9).is_err());
720 }
721
722 #[test]
723 fn all_twelve_primitive_setters_work() {
724 let cases: alloc::vec::Vec<(&str, MemberId, TypeKind)> = alloc::vec![
726 ("b", 1, TypeKind::Boolean),
727 ("by", 2, TypeKind::Byte),
728 ("i8", 3, TypeKind::Int8),
729 ("u8", 4, TypeKind::UInt8),
730 ("i16", 5, TypeKind::Int16),
731 ("u16", 6, TypeKind::UInt16),
732 ("i32", 7, TypeKind::Int32),
733 ("u32", 8, TypeKind::UInt32),
734 ("i64", 9, TypeKind::Int64),
735 ("u64", 10, TypeKind::UInt64),
736 ("f32", 11, TypeKind::Float32),
737 ("f64", 12, TypeKind::Float64),
738 ("c8", 13, TypeKind::Char8),
739 ("c16", 14, TypeKind::Char16),
740 ];
741 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
742 for (n, id, k) in &cases {
743 b.add_struct_member(
744 *n,
745 *id,
746 TypeDescriptor::primitive(*k, super::super::type_::primitive_name(*k)),
747 )
748 .unwrap();
749 }
750 b.add_struct_member("s", 100, TypeDescriptor::string8(64))
752 .unwrap();
753 b.add_struct_member("w", 101, TypeDescriptor::string16(64))
754 .unwrap();
755 let t = b.build().unwrap();
756 let mut d = DynamicData::new(t);
757 d.set_boolean_value(1, true).unwrap();
758 d.set_byte_value(2, 0xFF).unwrap();
759 d.set_int8_value(3, -1).unwrap();
760 d.set_uint8_value(4, 255).unwrap();
761 d.set_int16_value(5, -2).unwrap();
762 d.set_uint16_value(6, 2).unwrap();
763 d.set_int32_value(7, -3).unwrap();
764 d.set_uint32_value(8, 3).unwrap();
765 d.set_int64_value(9, -4).unwrap();
766 d.set_uint64_value(10, 4).unwrap();
767 d.set_float32_value(11, 1.5).unwrap();
768 d.set_float64_value(12, 2.5).unwrap();
769 d.set_char8_value(13, b'A').unwrap();
770 d.set_char16_value(14, 0x42).unwrap();
771 d.set_string_value(100, "abc").unwrap();
772 d.set_wstring_value(101, alloc::vec![0x41, 0x42]).unwrap();
773
774 assert!(d.get_boolean_value(1).unwrap());
775 assert_eq!(d.get_byte_value(2).unwrap(), 0xFF);
776 assert_eq!(d.get_int8_value(3).unwrap(), -1);
777 assert_eq!(d.get_uint8_value(4).unwrap(), 255);
778 assert_eq!(d.get_int16_value(5).unwrap(), -2);
779 assert_eq!(d.get_uint16_value(6).unwrap(), 2);
780 assert_eq!(d.get_int32_value(7).unwrap(), -3);
781 assert_eq!(d.get_uint32_value(8).unwrap(), 3);
782 assert_eq!(d.get_int64_value(9).unwrap(), -4);
783 assert_eq!(d.get_uint64_value(10).unwrap(), 4);
784 assert!((d.get_float32_value(11).unwrap() - 1.5).abs() < 1e-6);
785 assert!((d.get_float64_value(12).unwrap() - 2.5).abs() < 1e-9);
786 assert_eq!(d.get_char8_value(13).unwrap(), b'A');
787 assert_eq!(d.get_char16_value(14).unwrap(), 0x42);
788 assert_eq!(d.get_string_value(100).unwrap(), "abc");
789 assert_eq!(d.get_wstring_value(101).unwrap(), alloc::vec![0x41, 0x42]);
790 }
791}