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(array_data.children_type.iter().map(DataType::from));
248 Ok(Self::new(type_, children, bitmap).into())
249 }
250
251 pub fn fields(&self) -> impl ExactSizeIterator<Item = &ArrayRef> {
253 self.children.iter()
254 }
255
256 pub fn field_at(&self, index: usize) -> &ArrayRef {
260 &self.children[index]
261 }
262
263 pub unsafe fn field_at_unchecked(&self, index: usize) -> &ArrayRef {
268 unsafe { self.children.get_unchecked(index) }
269 }
270
271 #[cfg(test)]
272 pub fn values_vec(&self) -> Vec<Option<StructValue>> {
273 use crate::types::ScalarRef;
274
275 self.iter()
276 .map(|v| v.map(|s| s.to_owned_scalar()))
277 .collect_vec()
278 }
279}
280
281impl EstimateSize for StructArray {
282 fn estimated_heap_size(&self) -> usize {
283 self.heap_size
284 }
285}
286
287impl From<DataChunk> for StructArray {
288 fn from(chunk: DataChunk) -> Self {
289 Self::new(
290 StructType::unnamed(chunk.columns().iter().map(|c| c.data_type())),
291 chunk.columns().to_vec(),
292 chunk.visibility().clone(),
293 )
294 }
295}
296
297#[derive(Clone, Debug, PartialEq, Eq, Default, Hash)]
298pub struct StructValue {
299 fields: Box<[Datum]>,
300}
301
302impl PartialOrd for StructValue {
303 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
304 Some(self.cmp(other))
305 }
306}
307
308impl Ord for StructValue {
309 fn cmp(&self, other: &Self) -> Ordering {
310 self.as_scalar_ref().cmp(&other.as_scalar_ref())
311 }
312}
313
314impl EstimateSize for StructValue {
315 fn estimated_heap_size(&self) -> usize {
316 self.fields
318 .iter()
319 .map(|datum| datum.estimated_heap_size())
320 .sum()
321 }
322}
323
324impl StructValue {
325 pub fn new(fields: Vec<Datum>) -> Self {
326 Self {
327 fields: fields.into_boxed_slice(),
328 }
329 }
330
331 pub fn empty() -> Self {
333 Self::new(vec![])
334 }
335
336 pub fn fields(&self) -> &[Datum] {
337 &self.fields
338 }
339
340 pub fn memcmp_deserialize<'a>(
341 fields: impl IntoIterator<Item = &'a DataType>,
342 deserializer: &mut memcomparable::Deserializer<impl Buf>,
343 ) -> memcomparable::Result<Self> {
344 fields
345 .into_iter()
346 .map(|field| memcmp_encoding::deserialize_datum_in_composite(field, deserializer))
347 .try_collect()
348 .map(Self::new)
349 }
350
351 pub fn from_str(s: &str, ty: &StructType) -> Result<Self, BoxedError> {
368 if !s.starts_with('(') {
370 return Err("Missing left parenthesis".into());
371 }
372 if !s.ends_with(')') {
373 return Err("Missing right parenthesis".into());
374 }
375 let mut fields = Vec::with_capacity(s.len());
376 for (s, ty) in s[1..s.len() - 1].split(',').zip_eq_debug(ty.types()) {
377 let datum = match s.trim() {
378 "" => None,
379 s => Some(ScalarImpl::from_text(s, ty)?),
380 };
381 fields.push(datum);
382 }
383 Ok(StructValue::new(fields))
384 }
385}
386
387#[derive(Copy, Clone)]
388pub enum StructRef<'a> {
389 Indexed { arr: &'a StructArray, idx: usize },
390 ValueRef { val: &'a StructValue },
391}
392
393impl<'a> StructRef<'a> {
394 pub fn iter_fields_ref(self) -> impl ExactSizeIterator<Item = DatumRef<'a>> + 'a {
398 iter_fields_ref!(self, it, { Either::Left(it) }, { Either::Right(it) })
399 }
400
401 pub fn field_at(&self, i: usize) -> DatumRef<'a> {
405 match self {
406 StructRef::Indexed { arr, idx } => arr.field_at(i).value_at(*idx),
407 StructRef::ValueRef { val } => val.fields[i].to_datum_ref(),
408 }
409 }
410
411 pub unsafe fn field_at_unchecked(&self, i: usize) -> DatumRef<'a> {
416 unsafe {
417 match self {
418 StructRef::Indexed { arr, idx } => {
419 arr.field_at_unchecked(i).value_at_unchecked(*idx)
420 }
421 StructRef::ValueRef { val } => val.fields.get_unchecked(i).to_datum_ref(),
422 }
423 }
424 }
425
426 pub fn memcmp_serialize(
427 self,
428 serializer: &mut memcomparable::Serializer<impl BufMut>,
429 ) -> memcomparable::Result<()> {
430 iter_fields_ref!(self, it, {
431 for datum_ref in it {
432 memcmp_encoding::serialize_datum_in_composite(datum_ref, serializer)?
433 }
434 Ok(())
435 })
436 }
437
438 pub fn hash_scalar_inner<H: std::hash::Hasher>(self, state: &mut H) {
439 iter_fields_ref!(self, it, {
440 for datum_ref in it {
441 hash_datum(datum_ref, state);
442 }
443 })
444 }
445
446 pub fn estimate_serialize_size_inner(self) -> usize {
447 iter_fields_ref!(self, it, {
448 it.fold(0, |acc, datum_ref| {
449 acc + estimate_serialize_datum_size(datum_ref)
450 })
451 })
452 }
453}
454
455impl PartialEq for StructRef<'_> {
456 fn eq(&self, other: &Self) -> bool {
457 iter_fields_ref!(*self, lhs, {
458 iter_fields_ref!(*other, rhs, { lhs.eq(rhs) })
459 })
460 }
461}
462
463impl Eq for StructRef<'_> {}
464
465impl PartialOrd for StructRef<'_> {
466 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
467 Some(self.cmp(other))
468 }
469}
470
471impl Ord for StructRef<'_> {
472 fn cmp(&self, other: &Self) -> Ordering {
473 iter_fields_ref!(*self, lhs, {
474 iter_fields_ref!(*other, rhs, {
475 assert_eq!(lhs.len(), rhs.len());
476 lhs.cmp_by(rhs, |lv, rv| lv.default_cmp(&rv))
477 })
478 })
479 }
480}
481
482impl Debug for StructRef<'_> {
483 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
484 let mut is_first = true;
485 iter_fields_ref!(*self, it, {
486 for v in it {
487 if is_first {
488 write!(f, "{:?}", v)?;
489 is_first = false;
490 } else {
491 write!(f, ", {:?}", v)?;
492 }
493 }
494 Ok(())
495 })
496 }
497}
498
499impl ToText for StructRef<'_> {
500 fn write<W: std::fmt::Write>(&self, f: &mut W) -> std::fmt::Result {
501 let mut raw_text = String::new();
502 iter_fields_ref!(*self, it, {
503 write!(f, "(")?;
504 let mut is_first = true;
505 for x in it {
506 if is_first {
507 is_first = false;
508 } else {
509 write!(f, ",")?;
510 }
511 if x.is_some() {
513 raw_text.clear();
514 x.write(&mut raw_text)?;
515 quote_if_need(&raw_text, f)?;
516 }
517 }
518 write!(f, ")")
519 })
520 }
521
522 fn write_with_type<W: std::fmt::Write>(&self, ty: &DataType, f: &mut W) -> std::fmt::Result {
523 match ty {
524 DataType::Struct(_) => self.write(f),
525 _ => unreachable!(),
526 }
527 }
528}
529
530impl Row for StructRef<'_> {
532 fn datum_at(&self, index: usize) -> DatumRef<'_> {
533 self.field_at(index)
534 }
535
536 unsafe fn datum_at_unchecked(&self, index: usize) -> DatumRef<'_> {
537 unsafe { self.field_at_unchecked(index) }
538 }
539
540 fn len(&self) -> usize {
541 self.iter_fields_ref().len()
542 }
543
544 fn iter(&self) -> impl Iterator<Item = DatumRef<'_>> {
545 self.iter_fields_ref()
546 }
547}
548
549pub fn quote_if_need(input: &str, writer: &mut impl Write) -> std::fmt::Result {
551 if !input.is_empty() && !input.contains(
559 [
560 '"', '\\', ',',
561 ' ', '\t', '\n', '\r', '\x0B', '\x0C',
565 '(',')'
567]
568 ) {
569 return writer.write_str(input);
570 }
571
572 writer.write_char('"')?;
573
574 for ch in input.chars() {
575 match ch {
576 '"' => writer.write_str("\"\"")?,
577 '\\' => writer.write_str("\\\\")?,
578 _ => writer.write_char(ch)?,
579 }
580 }
581
582 writer.write_char('"')
583}
584
585#[cfg(test)]
586mod tests {
587 use more_asserts::assert_gt;
588
589 use super::*;
590 use crate::try_match_expand;
591 use crate::types::{F32, F64};
592
593 #[test]
596 fn test_struct_new_empty() {
597 let arr = StructArray::new(StructType::empty(), vec![], Bitmap::ones(0));
598 let actual = StructArray::from_protobuf(&arr.to_protobuf()).unwrap();
599 assert_eq!(ArrayImpl::Struct(arr), actual);
600 }
601
602 #[test]
603 fn test_struct_with_fields() {
604 use crate::array::*;
605 let arr = StructArray::new(
606 StructType::unnamed(vec![DataType::Int32, DataType::Float32]),
607 vec![
608 I32Array::from_iter([None, Some(1), None, Some(2)]).into_ref(),
609 F32Array::from_iter([None, Some(3.0), None, Some(4.0)]).into_ref(),
610 ],
611 [false, true, false, true].into_iter().collect(),
612 );
613 let actual = StructArray::from_protobuf(&arr.to_protobuf()).unwrap();
614 assert_eq!(ArrayImpl::Struct(arr), actual);
615
616 let arr = try_match_expand!(actual, ArrayImpl::Struct).unwrap();
617 let struct_values = arr.values_vec();
618 assert_eq!(
619 struct_values,
620 vec![
621 None,
622 Some(StructValue::new(vec![
623 Some(ScalarImpl::Int32(1)),
624 Some(ScalarImpl::Float32(3.0.into())),
625 ])),
626 None,
627 Some(StructValue::new(vec![
628 Some(ScalarImpl::Int32(2)),
629 Some(ScalarImpl::Float32(4.0.into())),
630 ])),
631 ]
632 );
633
634 let mut builder = StructArrayBuilder::with_type(
635 4,
636 DataType::Struct(StructType::unnamed(vec![
637 DataType::Int32,
638 DataType::Float32,
639 ])),
640 );
641 for v in &struct_values {
642 builder.append(v.as_ref().map(|s| s.as_scalar_ref()));
643 }
644 let arr = builder.finish();
645 assert_eq!(arr.values_vec(), struct_values);
646 }
647
648 #[test]
650 fn test_struct_create_builder() {
651 use crate::array::*;
652 let arr = StructArray::new(
653 StructType::unnamed(vec![DataType::Int32, DataType::Float32]),
654 vec![
655 I32Array::from_iter([Some(1)]).into_ref(),
656 F32Array::from_iter([Some(2.0)]).into_ref(),
657 ],
658 Bitmap::ones(1),
659 );
660 let builder = arr.create_builder(4);
661 let arr2 = builder.finish();
662 assert_eq!(arr.data_type(), arr2.data_type());
663 }
664
665 #[test]
666 fn test_struct_value_cmp() {
667 assert_gt!(
669 StructValue::new(vec![Some(1.into()), Some(2.0.into())]),
670 StructValue::new(vec![Some(1.into()), Some(1.0.into())]),
671 );
672 assert_gt!(
674 StructValue::new(vec![None]),
675 StructValue::new(vec![Some(1.into())]),
676 );
677 assert_gt!(
679 StructValue::new(vec![Some(1.into()), None, Some(3.into())]),
680 StructValue::new(vec![Some(1.into()), Some(1.0.into()), Some(2.into())]),
681 );
682 assert_eq!(
684 StructValue::new(vec![Some(1.into()), None]),
685 StructValue::new(vec![Some(1.into()), None]),
686 );
687 }
688
689 #[test]
690 fn test_serialize_deserialize() {
691 let value = StructValue::new(vec![
692 Some(F32::from(3.2).to_scalar_value()),
693 Some("abcde".into()),
694 Some(
695 StructValue::new(vec![
696 Some(F64::from(1.3).to_scalar_value()),
697 Some("a".into()),
698 None,
699 Some(StructValue::new(vec![]).to_scalar_value()),
700 ])
701 .to_scalar_value(),
702 ),
703 None,
704 Some("".into()),
705 None,
706 Some(StructValue::new(vec![]).to_scalar_value()),
707 Some(12345.to_scalar_value()),
708 ]);
709 let fields = [
710 DataType::Float32,
711 DataType::Varchar,
712 StructType::unnamed(vec![
713 DataType::Float64,
714 DataType::Varchar,
715 DataType::Varchar,
716 StructType::unnamed(vec![]).into(),
717 ])
718 .into(),
719 DataType::Int64,
720 DataType::Varchar,
721 DataType::Int16,
722 StructType::unnamed(vec![]).into(),
723 DataType::Int32,
724 ];
725 let struct_ref = StructRef::ValueRef { val: &value };
726 let mut serializer = memcomparable::Serializer::new(vec![]);
727 struct_ref.memcmp_serialize(&mut serializer).unwrap();
728 let buf = serializer.into_inner();
729 let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
730 assert_eq!(
731 StructValue::memcmp_deserialize(&fields, &mut deserializer).unwrap(),
732 value
733 );
734
735 let mut builder = StructArrayBuilder::with_type(
736 0,
737 DataType::Struct(StructType::unnamed(fields.to_vec())),
738 );
739
740 builder.append(Some(struct_ref));
741 let array = builder.finish();
742 let struct_ref = array.value_at(0).unwrap();
743 let mut serializer = memcomparable::Serializer::new(vec![]);
744 struct_ref.memcmp_serialize(&mut serializer).unwrap();
745 let buf = serializer.into_inner();
746 let mut deserializer = memcomparable::Deserializer::new(&buf[..]);
747 assert_eq!(
748 StructValue::memcmp_deserialize(&fields, &mut deserializer).unwrap(),
749 value
750 );
751 }
752
753 #[test]
754 fn test_memcomparable() {
755 let cases = [
756 (
757 StructValue::new(vec![
758 Some(123.to_scalar_value()),
759 Some(456i64.to_scalar_value()),
760 ]),
761 StructValue::new(vec![
762 Some(123.to_scalar_value()),
763 Some(789i64.to_scalar_value()),
764 ]),
765 vec![DataType::Int32, DataType::Int64],
766 Ordering::Less,
767 ),
768 (
769 StructValue::new(vec![
770 Some(123.to_scalar_value()),
771 Some(456i64.to_scalar_value()),
772 ]),
773 StructValue::new(vec![
774 Some(1.to_scalar_value()),
775 Some(789i64.to_scalar_value()),
776 ]),
777 vec![DataType::Int32, DataType::Int64],
778 Ordering::Greater,
779 ),
780 (
781 StructValue::new(vec![Some("".into())]),
782 StructValue::new(vec![None]),
783 vec![DataType::Varchar],
784 Ordering::Less,
785 ),
786 (
787 StructValue::new(vec![Some("abcd".into()), None]),
788 StructValue::new(vec![
789 Some("abcd".into()),
790 Some(StructValue::new(vec![Some("abcdef".into())]).to_scalar_value()),
791 ]),
792 vec![
793 DataType::Varchar,
794 StructType::unnamed(vec![DataType::Varchar]).into(),
795 ],
796 Ordering::Greater,
797 ),
798 (
799 StructValue::new(vec![
800 Some("abcd".into()),
801 Some(StructValue::new(vec![Some("abcdef".into())]).to_scalar_value()),
802 ]),
803 StructValue::new(vec![
804 Some("abcd".into()),
805 Some(StructValue::new(vec![Some("abcdef".into())]).to_scalar_value()),
806 ]),
807 vec![
808 DataType::Varchar,
809 StructType::unnamed(vec![DataType::Varchar]).into(),
810 ],
811 Ordering::Equal,
812 ),
813 ];
814
815 for (lhs, rhs, fields, order) in cases {
816 let lhs_serialized = {
817 let mut serializer = memcomparable::Serializer::new(vec![]);
818 StructRef::ValueRef { val: &lhs }
819 .memcmp_serialize(&mut serializer)
820 .unwrap();
821 serializer.into_inner()
822 };
823 let rhs_serialized = {
824 let mut serializer = memcomparable::Serializer::new(vec![]);
825 StructRef::ValueRef { val: &rhs }
826 .memcmp_serialize(&mut serializer)
827 .unwrap();
828 serializer.into_inner()
829 };
830 assert_eq!(lhs_serialized.cmp(&rhs_serialized), order);
831
832 let mut builder = StructArrayBuilder::with_type(
833 0,
834 DataType::Struct(StructType::unnamed(fields.clone())),
835 );
836 builder.append(Some(StructRef::ValueRef { val: &lhs }));
837 builder.append(Some(StructRef::ValueRef { val: &rhs }));
838 let array = builder.finish();
839 let lhs_serialized = {
840 let mut serializer = memcomparable::Serializer::new(vec![]);
841 array
842 .value_at(0)
843 .unwrap()
844 .memcmp_serialize(&mut serializer)
845 .unwrap();
846 serializer.into_inner()
847 };
848 let rhs_serialized = {
849 let mut serializer = memcomparable::Serializer::new(vec![]);
850 array
851 .value_at(1)
852 .unwrap()
853 .memcmp_serialize(&mut serializer)
854 .unwrap();
855 serializer.into_inner()
856 };
857 assert_eq!(lhs_serialized.cmp(&rhs_serialized), order);
858 }
859 }
860
861 #[test]
862 fn test_quote() {
863 #[track_caller]
864 fn test(input: &str, quoted: &str) {
865 let mut actual = String::new();
866 quote_if_need(input, &mut actual).unwrap();
867 assert_eq!(quoted, actual);
868 }
869 test("abc", "abc");
870 test("", r#""""#);
871 test(" x ", r#"" x ""#);
872 test("a b", r#""a b""#);
873 test(r#"a"bc"#, r#""a""bc""#);
874 test(r#"a\bc"#, r#""a\\bc""#);
875 test("{1}", "{1}");
876 test("{1,2}", r#""{1,2}""#);
877 test(r#"{"f": 1}"#, r#""{""f"": 1}""#);
878 }
879}