1#![allow(unsafe_op_in_unsafe_fn)]
2
3use std::string::String;
4use std::vec::Vec;
5
6#[cfg(target_arch = "aarch64")]
7use core::arch::aarch64::*;
8
9const fn build_escape_table() -> [u8; 256] {
16 let mut t = [0u8; 256];
17 let mut i = 0u8;
19 loop {
21 if i >= 0x20 {
22 break;
23 }
24 t[i as usize] = b'u'; i += 1;
26 }
27 t[b'"' as usize] = b'"';
29 t[b'\\' as usize] = b'\\';
30 t[b'\n' as usize] = b'n';
31 t[b'\r' as usize] = b'r';
32 t[b'\t' as usize] = b't';
33 t[0x08] = b'b'; t[0x0C] = b'f'; t
36}
37
38pub static ESCAPE_TABLE: [u8; 256] = build_escape_table();
40
41#[cfg(target_arch = "aarch64")]
47static BITMASK: [u8; 16] = [1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128];
48
49#[cfg(target_arch = "aarch64")]
52#[inline(always)]
53unsafe fn neon_movemask_u8x16(v: uint8x16_t) -> u16 {
54 let bm = vld1q_u8(BITMASK.as_ptr());
55 let t = vandq_u8(v, bm);
56 let p1 = vpaddq_u8(t, t);
57 let p2 = vpaddq_u8(p1, p1);
58 let p3 = vpaddq_u8(p2, p2);
59 vgetq_lane_u64(vreinterpretq_u64_u8(p3), 0) as u16
60}
61
62#[cfg(target_arch = "aarch64")]
66#[inline(always)]
67unsafe fn bulk_movemask_4x16(
68 c0: uint8x16_t,
69 c1: uint8x16_t,
70 c2: uint8x16_t,
71 c3: uint8x16_t,
72) -> u64 {
73 let bm = vld1q_u8(BITMASK.as_ptr());
74 let t0 = vandq_u8(c0, bm);
75 let t1 = vandq_u8(c1, bm);
76 let t2 = vandq_u8(c2, bm);
77 let t3 = vandq_u8(c3, bm);
78 let p01 = vpaddq_u8(t0, t1);
79 let p23 = vpaddq_u8(t2, t3);
80 let p0123 = vpaddq_u8(p01, p23);
81 let r = vpaddq_u8(p0123, p0123);
82 vgetq_lane_u64(vreinterpretq_u64_u8(r), 0)
83}
84
85#[cfg(target_arch = "aarch64")]
87#[inline(always)]
88unsafe fn escape_mask_neon_x64(ptr: *const u8) -> u64 {
89 let v0 = vld1q_u8(ptr);
90 let v1 = vld1q_u8(ptr.add(16));
91 let v2 = vld1q_u8(ptr.add(32));
92 let v3 = vld1q_u8(ptr.add(48));
93 let quote = vdupq_n_u8(b'"');
94 let bslash = vdupq_n_u8(b'\\');
95 let ctrl = vdupq_n_u8(0x20);
96 let m0 = vorrq_u8(
97 vorrq_u8(vceqq_u8(v0, quote), vceqq_u8(v0, bslash)),
98 vcltq_u8(v0, ctrl),
99 );
100 let m1 = vorrq_u8(
101 vorrq_u8(vceqq_u8(v1, quote), vceqq_u8(v1, bslash)),
102 vcltq_u8(v1, ctrl),
103 );
104 let m2 = vorrq_u8(
105 vorrq_u8(vceqq_u8(v2, quote), vceqq_u8(v2, bslash)),
106 vcltq_u8(v2, ctrl),
107 );
108 let m3 = vorrq_u8(
109 vorrq_u8(vceqq_u8(v3, quote), vceqq_u8(v3, bslash)),
110 vcltq_u8(v3, ctrl),
111 );
112 bulk_movemask_4x16(m0, m1, m2, m3)
113}
114
115#[cfg(target_arch = "aarch64")]
117#[inline(always)]
118unsafe fn escape_mask_neon_x32(ptr: *const u8) -> u32 {
119 let v0 = vld1q_u8(ptr);
120 let v1 = vld1q_u8(ptr.add(16));
121 let quote = vdupq_n_u8(b'"');
122 let bslash = vdupq_n_u8(b'\\');
123 let ctrl = vdupq_n_u8(0x20);
124 let m0 = vorrq_u8(
125 vorrq_u8(vceqq_u8(v0, quote), vceqq_u8(v0, bslash)),
126 vcltq_u8(v0, ctrl),
127 );
128 let m1 = vorrq_u8(
129 vorrq_u8(vceqq_u8(v1, quote), vceqq_u8(v1, bslash)),
130 vcltq_u8(v1, ctrl),
131 );
132 (neon_movemask_u8x16(m0) as u32) | ((neon_movemask_u8x16(m1) as u32) << 16)
133}
134
135#[cfg(target_arch = "aarch64")]
137#[inline(always)]
138unsafe fn escape_mask_neon_x16(ptr: *const u8) -> u16 {
139 let v = vld1q_u8(ptr);
140 let quote = vceqq_u8(v, vdupq_n_u8(b'"'));
141 let bslash = vceqq_u8(v, vdupq_n_u8(b'\\'));
142 let ctrl = vcltq_u8(v, vdupq_n_u8(0x20));
143 neon_movemask_u8x16(vorrq_u8(vorrq_u8(quote, bslash), ctrl))
144}
145
146#[cfg(target_arch = "x86_64")]
148#[target_feature(enable = "avx2")]
149unsafe fn escape_mask_avx2_x2(ptr: *const u8) -> u64 {
150 use core::arch::x86_64::*;
151 let d0 = _mm256_loadu_si256(ptr as *const __m256i);
152 let d1 = _mm256_loadu_si256(ptr.add(32) as *const __m256i);
153 let q = _mm256_set1_epi8(b'"' as i8);
154 let b = _mm256_set1_epi8(b'\\' as i8);
155 let c = _mm256_set1_epi8(0x20);
156 let m0 = _mm256_or_si256(
157 _mm256_cmpeq_epi8(d0, q),
158 _mm256_or_si256(_mm256_cmpeq_epi8(d0, b), _mm256_cmpgt_epi8(c, d0)),
159 );
160 let m1 = _mm256_or_si256(
161 _mm256_cmpeq_epi8(d1, q),
162 _mm256_or_si256(_mm256_cmpeq_epi8(d1, b), _mm256_cmpgt_epi8(c, d1)),
163 );
164 (_mm256_movemask_epi8(m0) as u32 as u64) | ((_mm256_movemask_epi8(m1) as u32 as u64) << 32)
165}
166
167#[cfg(target_arch = "x86_64")]
169#[target_feature(enable = "avx2")]
170unsafe fn escape_mask_avx2(ptr: *const u8) -> u32 {
171 use core::arch::x86_64::*;
172 let data = _mm256_loadu_si256(ptr as *const __m256i);
173 let q = _mm256_set1_epi8(b'"' as i8);
174 let b = _mm256_set1_epi8(b'\\' as i8);
175 let c = _mm256_set1_epi8(0x20);
176 let mask = _mm256_or_si256(
177 _mm256_cmpeq_epi8(data, q),
178 _mm256_or_si256(_mm256_cmpeq_epi8(data, b), _mm256_cmpgt_epi8(c, data)),
179 );
180 _mm256_movemask_epi8(mask) as u32
181}
182
183macro_rules! drain_escape_vec {
190 ($buf:expr, $bytes:expr, $start:expr, $base:expr, $mask:expr) => {{
191 let mut m = $mask;
192 while m != 0 {
193 let tz = m.trailing_zeros() as usize;
194 m &= m.wrapping_sub(1);
195 let pos = $base + tz;
196 if $start < pos {
197 $buf.extend_from_slice(unsafe { $bytes.get_unchecked($start..pos) });
198 }
199 let byte = unsafe { *$bytes.get_unchecked(pos) };
200 let esc = unsafe { *ESCAPE_TABLE.get_unchecked(byte as usize) };
201 match esc {
202 b'u' => {
203 $buf.extend_from_slice(b"\\u00");
204 let hi = (byte >> 4) & 0xF;
205 let lo = byte & 0xF;
206 $buf.push(if hi < 10 { b'0' + hi } else { b'a' + hi - 10 });
207 $buf.push(if lo < 10 { b'0' + lo } else { b'a' + lo - 10 });
208 }
209 c => {
210 $buf.push(b'\\');
211 $buf.push(c);
212 }
213 }
214 $start = pos + 1;
215
216 if m != 0 {
218 let tz = m.trailing_zeros() as usize;
219 m &= m.wrapping_sub(1);
220 let pos = $base + tz;
221 if $start < pos {
222 $buf.extend_from_slice(unsafe { $bytes.get_unchecked($start..pos) });
223 }
224 let byte = unsafe { *$bytes.get_unchecked(pos) };
225 let esc = unsafe { *ESCAPE_TABLE.get_unchecked(byte as usize) };
226 match esc {
227 b'u' => {
228 $buf.extend_from_slice(b"\\u00");
229 let hi = (byte >> 4) & 0xF;
230 let lo = byte & 0xF;
231 $buf.push(if hi < 10 { b'0' + hi } else { b'a' + hi - 10 });
232 $buf.push(if lo < 10 { b'0' + lo } else { b'a' + lo - 10 });
233 }
234 c => {
235 $buf.push(b'\\');
236 $buf.push(c);
237 }
238 }
239 $start = pos + 1;
240 }
241 }
242 }};
243}
244
245macro_rules! drain_escape_raw {
247 ($curr:expr, $bytes:expr, $start:expr, $base:expr, $mask:expr) => {{
248 let mut m = $mask;
249 while m != 0 {
250 let tz = m.trailing_zeros() as usize;
251 m &= m.wrapping_sub(1);
252 let pos = $base + tz;
253 if $start < pos {
254 let chunk = $bytes.get_unchecked($start..pos);
255 std::ptr::copy_nonoverlapping(chunk.as_ptr(), $curr, chunk.len());
256 $curr = $curr.add(chunk.len());
257 }
258 let byte = *$bytes.get_unchecked(pos);
259 let esc = *ESCAPE_TABLE.get_unchecked(byte as usize);
260 match esc {
261 b'u' => {
262 std::ptr::copy_nonoverlapping(b"\\u00".as_ptr(), $curr, 4);
263 $curr = $curr.add(4);
264 let hi = (byte >> 4) & 0xF;
265 let lo = byte & 0xF;
266 *$curr = if hi < 10 { b'0' + hi } else { b'a' + hi - 10 };
267 $curr = $curr.add(1);
268 *$curr = if lo < 10 { b'0' + lo } else { b'a' + lo - 10 };
269 $curr = $curr.add(1);
270 }
271 c => {
272 *$curr = b'\\';
273 $curr = $curr.add(1);
274 *$curr = c;
275 $curr = $curr.add(1);
276 }
277 }
278 $start = pos + 1;
279
280 if m != 0 {
282 let tz = m.trailing_zeros() as usize;
283 m &= m.wrapping_sub(1);
284 let pos = $base + tz;
285 if $start < pos {
286 let chunk = $bytes.get_unchecked($start..pos);
287 std::ptr::copy_nonoverlapping(chunk.as_ptr(), $curr, chunk.len());
288 $curr = $curr.add(chunk.len());
289 }
290 let byte = *$bytes.get_unchecked(pos);
291 let esc = *ESCAPE_TABLE.get_unchecked(byte as usize);
292 match esc {
293 b'u' => {
294 std::ptr::copy_nonoverlapping(b"\\u00".as_ptr(), $curr, 4);
295 $curr = $curr.add(4);
296 let hi = (byte >> 4) & 0xF;
297 let lo = byte & 0xF;
298 *$curr = if hi < 10 { b'0' + hi } else { b'a' + hi - 10 };
299 $curr = $curr.add(1);
300 *$curr = if lo < 10 { b'0' + lo } else { b'a' + lo - 10 };
301 $curr = $curr.add(1);
302 }
303 c => {
304 *$curr = b'\\';
305 $curr = $curr.add(1);
306 *$curr = c;
307 $curr = $curr.add(1);
308 }
309 }
310 $start = pos + 1;
311 }
312 }
313 }};
314}
315
316#[inline]
326pub fn write_str_escape(buf: &mut Vec<u8>, bytes: &[u8]) {
327 buf.push(b'"');
328 let len = bytes.len();
329 let mut i = 0usize;
330 let mut start = 0usize;
331 buf.reserve(len + 2);
332
333 #[cfg(target_arch = "aarch64")]
334 {
335 while i + 64 <= len {
336 let mask = unsafe { escape_mask_neon_x64(bytes.as_ptr().add(i)) };
337 if mask == 0 {
338 i += 64;
339 continue;
340 }
341 drain_escape_vec!(buf, bytes, start, i, mask);
342 i += 64;
343 }
344 while i + 32 <= len {
345 let mask = unsafe { escape_mask_neon_x32(bytes.as_ptr().add(i)) } as u64;
346 if mask == 0 {
347 i += 32;
348 continue;
349 }
350 drain_escape_vec!(buf, bytes, start, i, mask);
351 i += 32;
352 }
353 while i + 16 <= len {
354 let mask = unsafe { escape_mask_neon_x16(bytes.as_ptr().add(i)) } as u64;
355 if mask == 0 {
356 i += 16;
357 continue;
358 }
359 drain_escape_vec!(buf, bytes, start, i, mask);
360 i += 16;
361 }
362 }
363
364 #[cfg(target_arch = "x86_64")]
365 {
366 if is_x86_feature_detected!("avx2") {
367 while i + 64 <= len {
368 let mask = unsafe { escape_mask_avx2_x2(bytes.as_ptr().add(i)) };
369 if mask == 0 {
370 i += 64;
371 continue;
372 }
373 drain_escape_vec!(buf, bytes, start, i, mask);
374 i += 64;
375 }
376 while i + 32 <= len {
377 let mask = unsafe { escape_mask_avx2(bytes.as_ptr().add(i)) } as u64;
378 if mask == 0 {
379 i += 32;
380 continue;
381 }
382 drain_escape_vec!(buf, bytes, start, i, mask);
383 i += 32;
384 }
385 }
386 }
387
388 #[cold]
389 fn scalar_tail(buf: &mut Vec<u8>, bytes: &[u8], mut i: usize, mut start: usize) {
390 let len = bytes.len();
391 while i < len {
392 let b = unsafe { *bytes.get_unchecked(i) };
393 let esc = unsafe { *ESCAPE_TABLE.get_unchecked(b as usize) };
394 if esc != 0 {
395 if start < i {
396 buf.extend_from_slice(unsafe { bytes.get_unchecked(start..i) });
397 }
398 match esc {
399 b'u' => {
400 buf.extend_from_slice(b"\\u00");
401 let hi = (b >> 4) & 0xF;
402 let lo = b & 0xF;
403 buf.push(if hi < 10 { b'0' + hi } else { b'a' + hi - 10 });
404 buf.push(if lo < 10 { b'0' + lo } else { b'a' + lo - 10 });
405 }
406 c => {
407 buf.push(b'\\');
408 buf.push(c);
409 }
410 }
411 start = i + 1;
412 }
413 i += 1;
414 }
415 if start < len {
416 buf.extend_from_slice(unsafe { bytes.get_unchecked(start..len) });
417 }
418 }
419
420 if i < len {
421 scalar_tail(buf, bytes, i, start);
422 } else {
423 if start < len {
424 buf.extend_from_slice(unsafe { bytes.get_unchecked(start..len) });
425 }
426 }
427 buf.push(b'"');
428}
429
430#[inline]
435pub unsafe fn write_str_escape_raw(mut curr: *mut u8, bytes: &[u8]) -> *mut u8 {
436 *curr = b'"';
437 curr = curr.add(1);
438 let len = bytes.len();
439 let mut i = 0usize;
440 let mut start = 0usize;
441
442 #[cfg(target_arch = "aarch64")]
443 {
444 while i + 64 <= len {
445 let mask = escape_mask_neon_x64(bytes.as_ptr().add(i));
446 if mask == 0 {
447 i += 64;
448 continue;
449 }
450 drain_escape_raw!(curr, bytes, start, i, mask);
451 i += 64;
452 }
453 while i + 32 <= len {
454 let mask = escape_mask_neon_x32(bytes.as_ptr().add(i)) as u64;
455 if mask == 0 {
456 i += 32;
457 continue;
458 }
459 drain_escape_raw!(curr, bytes, start, i, mask);
460 i += 32;
461 }
462 while i + 16 <= len {
463 let mask = escape_mask_neon_x16(bytes.as_ptr().add(i)) as u64;
464 if mask == 0 {
465 i += 16;
466 continue;
467 }
468 drain_escape_raw!(curr, bytes, start, i, mask);
469 i += 16;
470 }
471 }
472
473 #[cfg(target_arch = "x86_64")]
474 {
475 if is_x86_feature_detected!("avx2") {
476 while i + 64 <= len {
477 let mask = escape_mask_avx2_x2(bytes.as_ptr().add(i));
478 if mask == 0 {
479 i += 64;
480 continue;
481 }
482 drain_escape_raw!(curr, bytes, start, i, mask);
483 i += 64;
484 }
485 while i + 32 <= len {
486 let mask = escape_mask_avx2(bytes.as_ptr().add(i)) as u64;
487 if mask == 0 {
488 i += 32;
489 continue;
490 }
491 drain_escape_raw!(curr, bytes, start, i, mask);
492 i += 32;
493 }
494 }
495 }
496
497 #[cold]
498 unsafe fn scalar_tail_raw(
499 mut curr: *mut u8,
500 bytes: &[u8],
501 mut i: usize,
502 mut start: usize,
503 ) -> *mut u8 {
504 let len = bytes.len();
505 while i < len {
506 let b = *bytes.get_unchecked(i);
507 let esc = *ESCAPE_TABLE.get_unchecked(b as usize);
508 if esc != 0 {
509 if start < i {
510 let chunk = bytes.get_unchecked(start..i);
511 std::ptr::copy_nonoverlapping(chunk.as_ptr(), curr, chunk.len());
512 curr = curr.add(chunk.len());
513 }
514 match esc {
515 b'u' => {
516 std::ptr::copy_nonoverlapping(b"\\u00".as_ptr(), curr, 4);
517 curr = curr.add(4);
518 let hi = (b >> 4) & 0xF;
519 let lo = b & 0xF;
520 *curr = if hi < 10 { b'0' + hi } else { b'a' + hi - 10 };
521 curr = curr.add(1);
522 *curr = if lo < 10 { b'0' + lo } else { b'a' + lo - 10 };
523 curr = curr.add(1);
524 }
525 c => {
526 *curr = b'\\';
527 curr = curr.add(1);
528 *curr = c;
529 curr = curr.add(1);
530 }
531 }
532 start = i + 1;
533 }
534 i += 1;
535 }
536
537 if start < len {
538 let chunk = bytes.get_unchecked(start..len);
539 std::ptr::copy_nonoverlapping(chunk.as_ptr(), curr, chunk.len());
540 curr = curr.add(chunk.len());
541 }
542 curr
543 }
544
545 if i < len {
546 curr = scalar_tail_raw(curr, bytes, i, start);
547 } else {
548 if start < len {
549 let chunk = bytes.get_unchecked(start..len);
550 std::ptr::copy_nonoverlapping(chunk.as_ptr(), curr, chunk.len());
551 curr = curr.add(chunk.len());
552 }
553 }
554
555 *curr = b'"';
556 curr.add(1)
557}
558
559pub trait Serialize {
563 fn serialize(&self, buf: &mut Vec<u8>);
564}
565
566pub trait SerializeRaw {
567 unsafe fn serialize_raw(&self, curr: *mut u8) -> *mut u8;
573}
574
575impl SerializeRaw for String {
576 #[inline(always)]
577 unsafe fn serialize_raw(&self, curr: *mut u8) -> *mut u8 {
578 unsafe { write_str_escape_raw(curr, self.as_bytes()) }
579 }
580}
581
582impl SerializeRaw for str {
583 #[inline(always)]
584 unsafe fn serialize_raw(&self, curr: *mut u8) -> *mut u8 {
585 unsafe { write_str_escape_raw(curr, self.as_bytes()) }
586 }
587}
588
589impl SerializeRaw for bool {
590 #[inline(always)]
591 unsafe fn serialize_raw(&self, curr: *mut u8) -> *mut u8 {
592 unsafe {
593 if *self {
594 std::ptr::copy_nonoverlapping(b"true".as_ptr(), curr, 4);
595 curr.add(4)
596 } else {
597 std::ptr::copy_nonoverlapping(b"false".as_ptr(), curr, 5);
598 curr.add(5)
599 }
600 }
601 }
602}
603
604impl Serialize for String {
605 #[inline(always)]
606 fn serialize(&self, buf: &mut Vec<u8>) {
607 write_str_escape(buf, self.as_bytes());
608 }
609}
610
611impl Serialize for str {
612 #[inline(always)]
613 fn serialize(&self, buf: &mut Vec<u8>) {
614 write_str_escape(buf, self.as_bytes());
615 }
616}
617
618impl Serialize for bool {
619 #[inline(always)]
620 fn serialize(&self, buf: &mut Vec<u8>) {
621 if *self {
622 buf.extend_from_slice(b"true");
623 } else {
624 buf.extend_from_slice(b"false");
625 }
626 }
627}
628
629macro_rules! impl_serialize_int {
630 ($($t:ty),*) => {
631 $(
632 impl Serialize for $t {
633 #[inline(always)]
634 fn serialize(&self, buf: &mut Vec<u8>) {
635 let mut buffer = itoa::Buffer::new();
636 buf.extend_from_slice(buffer.format(*self).as_bytes());
637 }
638 }
639
640 impl SerializeRaw for $t {
641 #[inline(always)]
642 unsafe fn serialize_raw(&self, curr: *mut u8) -> *mut u8 {
643 let mut buffer = itoa::Buffer::new();
644 let s = buffer.format(*self);
645 let len = s.len();
646 unsafe {
647 std::ptr::copy_nonoverlapping(s.as_ptr(), curr, len);
648 curr.add(len)
649 }
650 }
651 }
652 )*
653 };
654}
655
656impl_serialize_int!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
657
658macro_rules! impl_serialize_float {
659 ($($t:ty),*) => {
660 $(
661 impl Serialize for $t {
662 #[inline(always)]
663 fn serialize(&self, buf: &mut Vec<u8>) {
664 let mut buffer = ryu::Buffer::new();
665 buf.extend_from_slice(buffer.format(*self).as_bytes());
666 }
667 }
668
669 impl SerializeRaw for $t {
670 #[inline(always)]
671 unsafe fn serialize_raw(&self, curr: *mut u8) -> *mut u8 {
672 let mut buffer = ryu::Buffer::new();
673 let s = buffer.format(*self);
674 let len = s.len();
675 unsafe {
676 std::ptr::copy_nonoverlapping(s.as_ptr(), curr, len);
677 curr.add(len)
678 }
679 }
680 }
681 )*
682 };
683}
684
685impl_serialize_float!(f32, f64);
686
687#[inline(always)]
693pub unsafe fn write_value_raw<T: SerializeRaw + ?Sized>(val: &T, curr: *mut u8) -> *mut u8 {
694 unsafe { val.serialize_raw(curr) }
695}
696
697#[inline(always)]
699pub fn write_value<T: Serialize + ?Sized>(val: &T, buf: &mut Vec<u8>) {
700 val.serialize(buf);
701}
702
703impl<T: Serialize> Serialize for Vec<T> {
708 #[inline]
709 fn serialize(&self, buf: &mut Vec<u8>) {
710 self.as_slice().serialize(buf);
711 }
712}
713
714impl<T: Serialize> Serialize for [T] {
715 #[inline]
716 fn serialize(&self, buf: &mut Vec<u8>) {
717 buf.push(b'[');
718 for (i, item) in self.iter().enumerate() {
719 if i > 0 {
720 buf.push(b',');
721 }
722 item.serialize(buf);
723 }
724 buf.push(b']');
725 }
726}
727
728impl<T: Serialize + ?Sized> Serialize for &T {
729 #[inline(always)]
730 fn serialize(&self, buf: &mut Vec<u8>) {
731 (**self).serialize(buf);
732 }
733}
734
735impl<T: Serialize> Serialize for Option<T> {
736 #[inline]
737 fn serialize(&self, buf: &mut Vec<u8>) {
738 match self {
739 Some(v) => v.serialize(buf),
740 None => buf.extend_from_slice(b"null"),
741 }
742 }
743}
744
745impl<T: Serialize + ?Sized> Serialize for Box<T> {
746 #[inline(always)]
747 fn serialize(&self, buf: &mut Vec<u8>) {
748 self.as_ref().serialize(buf);
749 }
750}
751
752use std::borrow::Cow;
753impl<'a, T: Serialize + ?Sized + ToOwned> Serialize for Cow<'a, T> {
754 #[inline(always)]
755 fn serialize(&self, buf: &mut Vec<u8>) {
756 self.as_ref().serialize(buf);
757 }
758}
759impl<T: SerializeRaw> SerializeRaw for Vec<T> {
760 #[inline]
761 unsafe fn serialize_raw(&self, curr: *mut u8) -> *mut u8 {
762 unsafe { self.as_slice().serialize_raw(curr) }
763 }
764}
765
766impl<T: SerializeRaw> SerializeRaw for [T] {
767 #[inline]
768 unsafe fn serialize_raw(&self, mut curr: *mut u8) -> *mut u8 {
769 unsafe {
770 *curr = b'[';
771 curr = curr.add(1);
772 for (i, item) in self.iter().enumerate() {
773 if i > 0 {
774 *curr = b',';
775 curr = curr.add(1);
776 }
777 curr = item.serialize_raw(curr);
778 }
779 *curr = b']';
780 curr.add(1)
781 }
782 }
783}
784
785impl<T: SerializeRaw + ?Sized> SerializeRaw for &T {
786 #[inline(always)]
787 unsafe fn serialize_raw(&self, curr: *mut u8) -> *mut u8 {
788 unsafe { (**self).serialize_raw(curr) }
789 }
790}
791
792impl<T: SerializeRaw> SerializeRaw for Option<T> {
793 #[inline]
794 unsafe fn serialize_raw(&self, curr: *mut u8) -> *mut u8 {
795 unsafe {
796 match self {
797 Some(v) => v.serialize_raw(curr),
798 None => {
799 std::ptr::copy_nonoverlapping(b"null".as_ptr(), curr, 4);
800 curr.add(4)
801 }
802 }
803 }
804 }
805}
806
807impl<T: SerializeRaw + ?Sized> SerializeRaw for Box<T> {
808 #[inline(always)]
809 unsafe fn serialize_raw(&self, curr: *mut u8) -> *mut u8 {
810 unsafe { self.as_ref().serialize_raw(curr) }
811 }
812}
813
814impl<'a, T: SerializeRaw + ?Sized + ToOwned> SerializeRaw for Cow<'a, T> {
815 #[inline(always)]
816 unsafe fn serialize_raw(&self, curr: *mut u8) -> *mut u8 {
817 unsafe { self.as_ref().serialize_raw(curr) }
818 }
819}