1use std::cmp::Ordering;
16use std::fmt::{self, Debug, Write};
17use std::hash::Hash;
18use std::sync::Arc;
19
20use bytes::{Buf, BufMut};
21use either::Either;
22use itertools::Itertools;
23use risingwave_common_estimate_size::EstimateSize;
24use risingwave_pb::data::{PbArray, PbArrayType, StructArrayData};
25
26use super::{Array, ArrayBuilder, ArrayBuilderImpl, ArrayImpl, ArrayResult, DataChunk};
27use crate::array::ArrayRef;
28use crate::bitmap::{Bitmap, BitmapBuilder};
29use crate::error::BoxedError;
30use crate::row::Row;
31use crate::types::{
32 DataType, Datum, DatumRef, DefaultOrd, Scalar, ScalarImpl, StructType, ToDatumRef, ToText,
33 hash_datum,
34};
35use crate::util::iter_util::{ZipEqDebug, ZipEqFast};
36use crate::util::memcmp_encoding;
37use crate::util::value_encoding::estimate_serialize_datum_size;
38
39macro_rules! iter_fields_ref {
40 ($self:expr, $it:ident, { $($body:tt)* }) => {
41 iter_fields_ref!($self, $it, { $($body)* }, { $($body)* })
42 };
43
44 ($self:expr, $it:ident, { $($l_body:tt)* }, { $($r_body:tt)* }) => {
45 match $self {
46 StructRef::Indexed { arr, idx } => {
47 let $it = arr.children.iter().map(move |a| a.value_at(idx));
48 $($l_body)*
49 }
50 StructRef::ValueRef { val } => {
51 let $it = val.fields.iter().map(ToDatumRef::to_datum_ref);
52 $($r_body)*
53 }
54 }
55 }
56}
57
58#[derive(Debug, Clone)]
59pub struct StructArrayBuilder {
60 bitmap: BitmapBuilder,
61 pub(super) children_array: Vec<ArrayBuilderImpl>,
62 type_: StructType,
63 len: usize,
64}
65
66impl ArrayBuilder for StructArrayBuilder {
67 type ArrayType = StructArray;
68
69 #[cfg(not(test))]
70 fn new(_capacity: usize) -> Self {
71 panic!("Must use with_type.")
72 }
73
74 #[cfg(test)]
75 fn new(capacity: usize) -> Self {
76 Self::with_type(capacity, DataType::Struct(StructType::empty()))
77 }
78
79 fn with_type(capacity: usize, ty: DataType) -> Self {
80 let DataType::Struct(ty) = ty else {
81 panic!("must be DataType::Struct");
82 };
83 let children_array = ty
84 .types()
85 .map(|a| a.create_array_builder(capacity))
86 .collect();
87 Self {
88 bitmap: BitmapBuilder::with_capacity(capacity),
89 children_array,
90 type_: ty,
91 len: 0,
92 }
93 }
94
95 fn append_n(&mut self, n: usize, value: Option<StructRef<'_>>) {
96 match value {
97 None => {
98 self.bitmap.append_n(n, false);
99 for child in &mut self.children_array {
100 child.append_n(n, Datum::None);
101 }
102 }
103 Some(v) => {
104 self.bitmap.append_n(n, true);
105 iter_fields_ref!(v, fields, {
106 for (child, f) in self.children_array.iter_mut().zip_eq_fast(fields) {
107 child.append_n(n, f);
108 }
109 });
110 }
111 }
112 self.len += n;
113 }
114
115 fn append_array(&mut self, other: &StructArray) {
116 self.bitmap.append_bitmap(&other.bitmap);
117 for (a, o) in self
118 .children_array
119 .iter_mut()
120 .zip_eq_fast(other.children.iter())
121 {
122 a.append_array(o);
123 }
124 self.len += other.len();
125 }
126
127 fn pop(&mut self) -> Option<()> {
128 if self.bitmap.pop().is_some() {
129 for child in &mut self.children_array {
130 child.pop().unwrap()
131 }
132 self.len -= 1;
133
134 Some(())
135 } else {
136 None
137 }
138 }
139
140 fn len(&self) -> usize {
141 self.bitmap.len()
142 }
143
144 fn finish(self) -> StructArray {
145 let children = self
146 .children_array
147 .into_iter()
148 .map(|b| Arc::new(b.finish()))
149 .collect::<Vec<ArrayRef>>();
150 StructArray::new(self.type_, children, self.bitmap.finish())
151 }
152}
153
154impl EstimateSize for StructArrayBuilder {
155 fn estimated_heap_size(&self) -> usize {
156 self.bitmap.estimated_heap_size()
157 + self
158 .children_array
159 .iter()
160 .map(|a| a.estimated_heap_size())
161 .sum::<usize>()
162 }
163}
164
165#[derive(Debug, Clone, PartialEq)]
166pub struct StructArray {
167 bitmap: Bitmap,
168 children: Box<[ArrayRef]>,
169 type_: StructType,
170 heap_size: usize,
171}
172
173impl Array for StructArray {
174 type Builder = StructArrayBuilder;
175 type OwnedItem = StructValue;
176 type RefItem<'a> = StructRef<'a>;
177
178 unsafe fn raw_value_at_unchecked(&self, idx: usize) -> StructRef<'_> {
179 StructRef::Indexed { arr: self, idx }
180 }
181
182 fn len(&self) -> usize {
183 self.bitmap.len()
184 }
185
186 fn to_protobuf(&self) -> PbArray {
187 let children_array = self.children.iter().map(|a| a.to_protobuf()).collect();
188 let children_type = self.type_.types().map(|t| t.to_protobuf()).collect();
189 PbArray {
190 array_type: PbArrayType::Struct as i32,
191 struct_array_data: Some(StructArrayData {
192 children_array,
193 children_type,
194 }),
195 list_array_data: None,
196 null_bitmap: Some(self.bitmap.to_protobuf()),
197 values: vec![],
198 }
199 }
200
201 fn null_bitmap(&self) -> &Bitmap {
202 &self.bitmap
203 }
204
205 fn into_null_bitmap(self) -> Bitmap {
206 self.bitmap
207 }
208
209 fn set_bitmap(&mut self, bitmap: Bitmap) {
210 self.bitmap = bitmap;
211 }
212
213 fn data_type(&self) -> DataType {
214 DataType::Struct(self.type_.clone())
215 }
216}
217
218impl StructArray {
219 pub fn new(type_: StructType, children: Vec<ArrayRef>, bitmap: Bitmap) -> Self {
220 let heap_size = bitmap.estimated_heap_size()
221 + children
222 .iter()
223 .map(|c| c.estimated_heap_size())
224 .sum::<usize>();
225
226 Self {
227 bitmap,
228 children: children.into(),
229 type_,
230 heap_size,
231 }
232 }
233
234 pub fn from_protobuf(array: &PbArray) -> ArrayResult<ArrayImpl> {
235 ensure!(
236 array.values.is_empty(),
237 "Must have no buffer in a struct array"
238 );
239 let bitmap: Bitmap = array.get_null_bitmap()?.into();
240 let cardinality = bitmap.len();
241 let array_data = array.get_struct_array_data()?;
242 let children = array_data
243 .children_array
244 .iter()
245 .map(|child| Ok(Arc::new(ArrayImpl::from_protobuf(child, cardinality)?)))
246 .collect::<ArrayResult<Vec<ArrayRef>>>()?;
247 let type_ = StructType::unnamed(
248 array_data
249 .children_type
250 .iter()
251 .map(DataType::from)
252 .collect(),
253 );
254 Ok(Self::new(type_, children, bitmap).into())
255 }
256
257 pub fn fields(&self) -> impl ExactSizeIterator<Item = &ArrayRef> {
259 self.children.iter()
260 }
261
262 pub fn field_at(&self, index: usize) -> &ArrayRef {
266 &self.children[index]
267 }
268
269 pub unsafe fn field_at_unchecked(&self, index: usize) -> &ArrayRef {
274 unsafe { self.children.get_unchecked(index) }
275 }
276
277 #[cfg(test)]
278 pub fn values_vec(&self) -> Vec<Option<StructValue>> {
279 use crate::types::ScalarRef;
280
281 self.iter()
282 .map(|v| v.map(|s| s.to_owned_scalar()))
283 .collect_vec()
284 }
285}
286
287impl EstimateSize for StructArray {
288 fn estimated_heap_size(&self) -> usize {
289 self.heap_size
290 }
291}
292
293impl From<DataChunk> for StructArray {
294 fn from(chunk: DataChunk) -> Self {
295 Self::new(
296 StructType::unnamed(chunk.columns().iter().map(|c| c.data_type()).collect()),
297 chunk.columns().to_vec(),
298 chunk.visibility().clone(),
299 )
300 }
301}
302
303#[derive(Clone, Debug, PartialEq, Eq, Default, Hash)]
304pub struct StructValue {
305 fields: Box<[Datum]>,
306}
307
308impl PartialOrd for StructValue {
309 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
310 Some(self.cmp(other))
311 }
312}
313
314impl Ord for StructValue {
315 fn cmp(&self, other: &Self) -> Ordering {
316 self.as_scalar_ref().cmp(&other.as_scalar_ref())
317 }
318}
319
320impl EstimateSize for StructValue {
321 fn estimated_heap_size(&self) -> usize {
322 self.fields
324 .iter()
325 .map(|datum| datum.estimated_heap_size())
326 .sum()
327 }
328}
329
330impl StructValue {
331 pub fn new(fields: Vec<Datum>) -> Self {
332 Self {
333 fields: fields.into_boxed_slice(),
334 }
335 }
336
337 pub fn empty() -> Self {
339 Self::new(vec![])
340 }
341
342 pub fn fields(&self) -> &[Datum] {
343 &self.fields
344 }
345
346 pub fn memcmp_deserialize<'a>(
347 fields: impl IntoIterator<Item = &'a DataType>,
348 deserializer: &mut memcomparable::Deserializer<impl Buf>,
349 ) -> memcomparable::Result<Self> {
350 fields
351 .into_iter()
352 .map(|field| memcmp_encoding::deserialize_datum_in_composite(field, deserializer))
353 .try_collect()
354 .map(Self::new)
355 }
356
357 pub fn from_str(s: &str, ty: &StructType) -> Result<Self, BoxedError> {
374 if !s.starts_with('(') {
376 return Err("Missing left parenthesis".into());
377 }
378 if !s.ends_with(')') {
379 return Err("Missing right parenthesis".into());
380 }
381 let mut fields = Vec::with_capacity(s.len());
382 for (s, ty) in s[1..s.len() - 1].split(',').zip_eq_debug(ty.types()) {
383 let datum = match s.trim() {
384 "" => None,
385 s => Some(ScalarImpl::from_text(s, ty)?),
386 };
387 fields.push(datum);
388 }
389 Ok(StructValue::new(fields))
390 }
391}
392
393#[derive(Copy, Clone)]
394pub enum StructRef<'a> {
395 Indexed { arr: &'a StructArray, idx: usize },
396 ValueRef { val: &'a StructValue },
397}
398
399impl<'a> StructRef<'a> {
400 pub fn iter_fields_ref(self) -> impl ExactSizeIterator<Item = DatumRef<'a>> + 'a {
404 iter_fields_ref!(self, it, { Either::Left(it) }, { Either::Right(it) })
405 }
406
407 pub fn field_at(&self, i: usize) -> DatumRef<'a> {
411 match self {
412 StructRef::Indexed { arr, idx } => arr.field_at(i).value_at(*idx),
413 StructRef::ValueRef { val } => val.fields[i].to_datum_ref(),
414 }
415 }
416
417 pub unsafe fn field_at_unchecked(&self, i: usize) -> DatumRef<'a> {
422 unsafe {
423 match self {
424 StructRef::Indexed { arr, idx } => {
425 arr.field_at_unchecked(i).value_at_unchecked(*idx)
426 }
427 StructRef::ValueRef { val } => val.fields.get_unchecked(i).to_datum_ref(),
428 }
429 }
430 }
431
432 pub fn memcmp_serialize(
433 self,
434 serializer: &mut memcomparable::Serializer<impl BufMut>,
435 ) -> memcomparable::Result<()> {
436 iter_fields_ref!(self, it, {
437 for datum_ref in it {
438 memcmp_encoding::serialize_datum_in_composite(datum_ref, serializer)?
439 }
440 Ok(())
441 })
442 }
443
444 pub fn hash_scalar_inner<H: std::hash::Hasher>(self, state: &mut H) {
445 iter_fields_ref!(self, it, {
446 for datum_ref in it {
447 hash_datum(datum_ref, state);
448 }
449 })
450 }
451
452 pub fn estimate_serialize_size_inner(self) -> usize {
453 iter_fields_ref!(self, it, {
454 it.fold(0, |acc, datum_ref| {
455 acc + estimate_serialize_datum_size(datum_ref)
456 })
457 })
458 }
459}
460
461impl PartialEq for StructRef<'_> {
462 fn eq(&self, other: &Self) -> bool {
463 iter_fields_ref!(*self, lhs, {
464 iter_fields_ref!(*other, rhs, { lhs.eq(rhs) })
465 })
466 }
467}
468
469impl Eq for StructRef<'_> {}
470
471impl PartialOrd for StructRef<'_> {
472 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
473 Some(self.cmp(other))
474 }
475}
476
477impl Ord for StructRef<'_> {
478 fn cmp(&self, other: &Self) -> Ordering {
479 iter_fields_ref!(*self, lhs, {
480 iter_fields_ref!(*other, rhs, {
481 assert_eq!(lhs.len(), rhs.len());
482 lhs.cmp_by(rhs, |lv, rv| lv.default_cmp(&rv))
483 })
484 })
485 }
486}
487
488impl Debug for StructRef<'_> {
489 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
490 let mut is_first = true;
491 iter_fields_ref!(*self, it, {
492 for v in it {
493 if is_first {
494 write!(f, "{:?}", v)?;
495 is_first = false;
496 } else {
497 write!(f, ", {:?}", v)?;
498 }
499 }
500 Ok(())
501 })
502 }
503}
504
505impl ToText for StructRef<'_> {
506 fn write<W: std::fmt::Write>(&self, f: &mut W) -> std::fmt::Result {
507 let mut raw_text = String::new();
508 iter_fields_ref!(*self, it, {
509 write!(f, "(")?;
510 let mut is_first = true;
511 for x in it {
512 if is_first {
513 is_first = false;
514 } else {
515 write!(f, ",")?;
516 }
517 if x.is_some() {
519 raw_text.clear();
520 x.write(&mut raw_text)?;
521 quote_if_need(&raw_text, f)?;
522 }
523 }
524 write!(f, ")")
525 })
526 }
527
528 fn write_with_type<W: std::fmt::Write>(&self, ty: &DataType, f: &mut W) -> std::fmt::Result {
529 match ty {
530 DataType::Struct(_) => self.write(f),
531 _ => unreachable!(),
532 }
533 }
534}
535
536impl Row for StructRef<'_> {
538 fn datum_at(&self, index: usize) -> DatumRef<'_> {
539 self.field_at(index)
540 }
541
542 unsafe fn datum_at_unchecked(&self, index: usize) -> DatumRef<'_> {
543 unsafe { self.field_at_unchecked(index) }
544 }
545
546 fn len(&self) -> usize {
547 self.iter_fields_ref().len()
548 }
549
550 fn iter(&self) -> impl Iterator<Item = DatumRef<'_>> {
551 self.iter_fields_ref()
552 }
553}
554
555pub fn quote_if_need(input: &str, writer: &mut impl Write) -> std::fmt::Result {
557 if !input.is_empty() && !input.contains(
565 [
566 '"', '\\', ',',
567 ' ', '\t', '\n', '\r', '\x0B', '\x0C',
571 '(',')'
573]
574 ) {
575 return writer.write_str(input);
576 }
577
578 writer.write_char('"')?;
579
580 for ch in input.chars() {
581 match ch {
582 '"' => writer.write_str("\"\"")?,
583 '\\' => writer.write_str("\\\\")?,
584 _ => writer.write_char(ch)?,
585 }
586 }
587
588 writer.write_char('"')
589}
590
591#[cfg(test)]
592mod tests {
593 use more_asserts::assert_gt;
594
595 use super::*;
596 use crate::try_match_expand;
597 use crate::types::{F32, F64};
598
599 #[test]
602 fn test_struct_new_empty() {
603 let arr = StructArray::new(StructType::empty(), vec![], Bitmap::ones(0));
604 let actual = StructArray::from_protobuf(&arr.to_protobuf()).unwrap();
605 assert_eq!(ArrayImpl::Struct(arr), actual);
606 }
607
608 #[test]
609 fn test_struct_with_fields() {
610 use crate::array::*;
611 let arr = StructArray::new(
612 StructType::unnamed(vec![DataType::Int32, DataType::Float32]),
613 vec![
614 I32Array::from_iter([None, Some(1), None, Some(2)]).into_ref(),
615 F32Array::from_iter([None, Some(3.0), None, Some(4.0)]).into_ref(),
616 ],
617 [false, true, false, true].into_iter().collect(),
618 );
619 let actual = StructArray::from_protobuf(&arr.to_protobuf()).unwrap();
620 assert_eq!(ArrayImpl::Struct(arr), actual);
621
622 let arr = try_match_expand!(actual, ArrayImpl::Struct).unwrap();
623 let struct_values = arr.values_vec();
624 assert_eq!(
625 struct_values,
626 vec![
627 None,
628 Some(StructValue::new(vec![
629 Some(ScalarImpl::Int32(1)),
630 Some(ScalarImpl::Float32(3.0.into())),
631 ])),
632 None,
633 Some(StructValue::new(vec![
634 Some(ScalarImpl::Int32(2)),
635 Some(ScalarImpl::Float32(4.0.into())),
636 ])),
637 ]
638 );
639
640 let mut builder = StructArrayBuilder::with_type(
641 4,
642 DataType::Struct(StructType::unnamed(vec![
643 DataType::Int32,
644 DataType::Float32,
645 ])),
646 );
647 for v in &struct_values {
648 builder.append(v.as_ref().map(|s| s.as_scalar_ref()));
649 }
650 let arr = builder.finish();
651 assert_eq!(arr.values_vec(), struct_values);
652 }
653
654 #[test]
656 fn test_struct_create_builder() {
657 use crate::array::*;
658 let arr = StructArray::new(
659 StructType::unnamed(vec![DataType::Int32, DataType::Float32]),
660 vec![
661 I32Array::from_iter([Some(1)]).into_ref(),
662 F32Array::from_iter([Some(2.0)]).into_ref(),
663 ],
664 Bitmap::ones(1),
665 );
666 let builder = arr.create_builder(4);
667 let arr2 = builder.finish();
668 assert_eq!(arr.data_type(), arr2.data_type());
669 }
670
671 #[test]
672 fn test_struct_value_cmp() {
673 assert_gt!(
675 StructValue::new(vec![Some(1.into()), Some(2.0.into())]),
676 StructValue::new(vec![Some(1.into()), Some(1.0.into())]),
677 );
678 assert_gt!(
680 StructValue::new(vec![None]),
681 StructValue::new(vec![Some(1.into())]),
682 );
683 assert_gt!(
685 StructValue::new(vec![Some(1.into()), None, Some(3.into())]),
686 StructValue::new(vec![Some(1.into()), Some(1.0.into()), Some(2.into())]),
687 );
688 assert_eq!(
690 StructValue::new(vec![Some(1.into()), None]),
691 StructValue::new(vec![Some(1.into()), None]),
692 );
693 }
694
695 #[test]
696 fn test_serialize_deserialize() {
697 let value = StructValue::new(vec![
698 Some(F32::from(3.2).to_scalar_value()),
699 Some("abcde".into()),
700 Some(
701 StructValue::new(vec![
702 Some(F64::from(1.3).to_scalar_value()),
703 Some("a".into()),
704 None,
705 Some(StructValue::new(vec![]).to_scalar_value()),
706 ])
707 .to_scalar_value(),
708 ),
709 None,
710 Some("".into()),
711 None,
712 Some(StructValue::new(vec![]).to_scalar_value()),
713 Some(12345.to_scalar_value()),
714 ]);
715 let fields = [
716 DataType::Float32,
717 DataType::Varchar,
718 StructType::unnamed(vec![
719 DataType::Float64,
720 DataType::Varchar,
721 DataType::Varchar,
722 StructType::unnamed(vec![]).into(),
723 ])
724 .into(),
725 DataType::Int64,
726 DataType::Varchar,
727 DataType::Int16,
728 StructType::unnamed(vec![]).into(),
729 DataType::Int32,
730 ];
731 let struct_ref = StructRef::ValueRef { val: &value };
732 let mut serializer = memcomparable::Serializer::new(vec![]);
733 struct_ref.memcmp_serialize(&mut serializer).unwrap();
734 let buf = serializer.into_inner();
735 let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
736 assert_eq!(
737 StructValue::memcmp_deserialize(&fields, &mut deserializer).unwrap(),
738 value
739 );
740
741 let mut builder = StructArrayBuilder::with_type(
742 0,
743 DataType::Struct(StructType::unnamed(fields.to_vec())),
744 );
745
746 builder.append(Some(struct_ref));
747 let array = builder.finish();
748 let struct_ref = array.value_at(0).unwrap();
749 let mut serializer = memcomparable::Serializer::new(vec![]);
750 struct_ref.memcmp_serialize(&mut serializer).unwrap();
751 let buf = serializer.into_inner();
752 let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
753 assert_eq!(
754 StructValue::memcmp_deserialize(&fields, &mut deserializer).unwrap(),
755 value
756 );
757 }
758
759 #[test]
760 fn test_memcomparable() {
761 let cases = [
762 (
763 StructValue::new(vec![
764 Some(123.to_scalar_value()),
765 Some(456i64.to_scalar_value()),
766 ]),
767 StructValue::new(vec![
768 Some(123.to_scalar_value()),
769 Some(789i64.to_scalar_value()),
770 ]),
771 vec![DataType::Int32, DataType::Int64],
772 Ordering::Less,
773 ),
774 (
775 StructValue::new(vec![
776 Some(123.to_scalar_value()),
777 Some(456i64.to_scalar_value()),
778 ]),
779 StructValue::new(vec![
780 Some(1.to_scalar_value()),
781 Some(789i64.to_scalar_value()),
782 ]),
783 vec![DataType::Int32, DataType::Int64],
784 Ordering::Greater,
785 ),
786 (
787 StructValue::new(vec![Some("".into())]),
788 StructValue::new(vec![None]),
789 vec![DataType::Varchar],
790 Ordering::Less,
791 ),
792 (
793 StructValue::new(vec![Some("abcd".into()), None]),
794 StructValue::new(vec![
795 Some("abcd".into()),
796 Some(StructValue::new(vec![Some("abcdef".into())]).to_scalar_value()),
797 ]),
798 vec![
799 DataType::Varchar,
800 StructType::unnamed(vec![DataType::Varchar]).into(),
801 ],
802 Ordering::Greater,
803 ),
804 (
805 StructValue::new(vec![
806 Some("abcd".into()),
807 Some(StructValue::new(vec![Some("abcdef".into())]).to_scalar_value()),
808 ]),
809 StructValue::new(vec![
810 Some("abcd".into()),
811 Some(StructValue::new(vec![Some("abcdef".into())]).to_scalar_value()),
812 ]),
813 vec![
814 DataType::Varchar,
815 StructType::unnamed(vec![DataType::Varchar]).into(),
816 ],
817 Ordering::Equal,
818 ),
819 ];
820
821 for (lhs, rhs, fields, order) in cases {
822 let lhs_serialized = {
823 let mut serializer = memcomparable::Serializer::new(vec![]);
824 StructRef::ValueRef { val: &lhs }
825 .memcmp_serialize(&mut serializer)
826 .unwrap();
827 serializer.into_inner()
828 };
829 let rhs_serialized = {
830 let mut serializer = memcomparable::Serializer::new(vec![]);
831 StructRef::ValueRef { val: &rhs }
832 .memcmp_serialize(&mut serializer)
833 .unwrap();
834 serializer.into_inner()
835 };
836 assert_eq!(lhs_serialized.cmp(&rhs_serialized), order);
837
838 let mut builder = StructArrayBuilder::with_type(
839 0,
840 DataType::Struct(StructType::unnamed(fields.to_vec())),
841 );
842 builder.append(Some(StructRef::ValueRef { val: &lhs }));
843 builder.append(Some(StructRef::ValueRef { val: &rhs }));
844 let array = builder.finish();
845 let lhs_serialized = {
846 let mut serializer = memcomparable::Serializer::new(vec![]);
847 array
848 .value_at(0)
849 .unwrap()
850 .memcmp_serialize(&mut serializer)
851 .unwrap();
852 serializer.into_inner()
853 };
854 let rhs_serialized = {
855 let mut serializer = memcomparable::Serializer::new(vec![]);
856 array
857 .value_at(1)
858 .unwrap()
859 .memcmp_serialize(&mut serializer)
860 .unwrap();
861 serializer.into_inner()
862 };
863 assert_eq!(lhs_serialized.cmp(&rhs_serialized), order);
864 }
865 }
866
867 #[test]
868 fn test_quote() {
869 #[track_caller]
870 fn test(input: &str, quoted: &str) {
871 let mut actual = String::new();
872 quote_if_need(input, &mut actual).unwrap();
873 assert_eq!(quoted, actual);
874 }
875 test("abc", "abc");
876 test("", r#""""#);
877 test(" x ", r#"" x ""#);
878 test("a b", r#""a b""#);
879 test(r#"a"bc"#, r#""a""bc""#);
880 test(r#"a\bc"#, r#""a\\bc""#);
881 test("{1}", "{1}");
882 test("{1,2}", r#""{1,2}""#);
883 test(r#"{"f": 1}"#, r#""{""f"": 1}""#);
884 }
885}