1use alloc::{string::String, sync::Arc, vec::Vec};
24use serde::{Serialize, Serializer};
25
26#[cfg(feature = "sso-lv20")]
28const SSO_BUFFER_SIZE: usize = 255; #[cfg(all(not(feature = "sso-lv20"), feature = "sso-lv10"))]
30const SSO_BUFFER_SIZE: usize = 127; #[cfg(all(
32 not(any(feature = "sso-lv20", feature = "sso-lv10")),
33 feature = "sso-min-64bit"
34))]
35const SSO_BUFFER_SIZE: usize = 31; #[cfg(all(
37 not(any(feature = "sso-lv20", feature = "sso-lv10", feature = "sso-min-64bit")),
38 feature = "sso-min-32bit"
39))]
40const SSO_BUFFER_SIZE: usize = 15; #[cfg(not(any(
42 feature = "sso-min-32bit",
43 feature = "sso-min-64bit",
44 feature = "sso-lv10",
45 feature = "sso-lv20"
46)))]
47#[allow(dead_code)]
48const SSO_BUFFER_SIZE: usize = 0; #[cfg(any(
52 feature = "sso-min-32bit",
53 feature = "sso-min-64bit",
54 feature = "sso-lv10",
55 feature = "sso-lv20"
56))]
57type LengthType = u8;
58
59#[cfg(not(any(
60 feature = "sso-min-32bit",
61 feature = "sso-min-64bit",
62 feature = "sso-lv10",
63 feature = "sso-lv20"
64)))]
65#[allow(dead_code)]
66type LengthType = u8;
67
68#[derive(Clone)]
75#[allow(clippy::large_enum_variant)]
76pub enum ArcPayload {
77 #[cfg(any(
78 feature = "sso-min-32bit",
79 feature = "sso-min-64bit",
80 feature = "sso-lv10",
81 feature = "sso-lv20"
82 ))]
83 Small([u8; SSO_BUFFER_SIZE], LengthType), Large {
85 data: Arc<[u8]>,
86 start: usize,
87 length: usize,
88 },
89}
90
91impl PartialEq for ArcPayload {
92 fn eq(&self, other: &Self) -> bool {
93 self.as_slice() == other.as_slice()
94 }
95}
96
97impl Eq for ArcPayload {}
98
99impl Serialize for ArcPayload {
100 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
101 where
102 S: Serializer,
103 {
104 self.as_slice().serialize(serializer)
105 }
106}
107
108impl ArcPayload {
109 pub fn new(data: Arc<[u8]>, start: usize, length: usize) -> Self {
134 debug_assert!(start + length <= data.len(), "payload out of bounds",);
135
136 #[cfg(any(
137 feature = "sso-min-32bit",
138 feature = "sso-min-64bit",
139 feature = "sso-lv10",
140 feature = "sso-lv20"
141 ))]
142 if length <= SSO_BUFFER_SIZE {
143 let mut buffer = [0u8; SSO_BUFFER_SIZE];
144 buffer[..length].copy_from_slice(&data[start..start + length]);
145 return Self::Small(buffer, length as LengthType);
146 }
147
148 Self::Large {
149 data,
150 start,
151 length,
152 }
153 }
154
155 pub fn as_slice(&self) -> &[u8] {
163 match self {
164 ArcPayload::Large {
165 data,
166 start,
167 length,
168 } => &data[*start..*start + *length],
169 #[cfg(any(
170 feature = "sso-min-32bit",
171 feature = "sso-min-64bit",
172 feature = "sso-lv10",
173 feature = "sso-lv20"
174 ))]
175 ArcPayload::Small(buffer, length) => &buffer[..*length as usize],
176 }
177 }
178
179 pub fn len(&self) -> usize {
187 match self {
188 ArcPayload::Large { length, .. } => *length,
189 #[cfg(any(
190 feature = "sso-min-32bit",
191 feature = "sso-min-64bit",
192 feature = "sso-lv10",
193 feature = "sso-lv20"
194 ))]
195 ArcPayload::Small(_, length) => *length as usize,
196 }
197 }
198
199 pub fn is_empty(&self) -> bool {
207 self.len() == 0
208 }
209
210 pub fn arc_data(&self) -> Option<&Arc<[u8]>> {
220 match self {
221 ArcPayload::Large { data, .. } => Some(data),
222 #[cfg(any(
223 feature = "sso-min-32bit",
224 feature = "sso-min-64bit",
225 feature = "sso-lv10",
226 feature = "sso-lv20"
227 ))]
228 ArcPayload::Small(_, _) => None, }
230 }
231}
232
233impl Default for ArcPayload {
234 fn default() -> Self {
235 #[cfg(any(
236 feature = "sso-min-32bit",
237 feature = "sso-min-64bit",
238 feature = "sso-lv10",
239 feature = "sso-lv20"
240 ))]
241 return ArcPayload::Small([0u8; SSO_BUFFER_SIZE], 0 as LengthType);
242
243 #[cfg(not(any(
244 feature = "sso-min-32bit",
245 feature = "sso-min-64bit",
246 feature = "sso-lv10",
247 feature = "sso-lv20"
248 )))]
249 return ArcPayload::Large {
250 data: Arc::from(&[] as &[u8]),
251 start: 0,
252 length: 0,
253 };
254 }
255}
256
257impl core::fmt::Debug for ArcPayload {
258 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
259 f.debug_struct("ArcPayload")
260 .field("data", &self.as_slice())
261 .field("len", &self.len())
262 .finish()
263 }
264}
265
266pub trait IntoPayload {
272 fn into_payload(self) -> ArcPayload;
278}
279
280impl IntoPayload for &str {
282 fn into_payload(self) -> ArcPayload {
283 let bytes = self.as_bytes();
284
285 #[cfg(any(
286 feature = "sso-min-32bit",
287 feature = "sso-min-64bit",
288 feature = "sso-lv10",
289 feature = "sso-lv20"
290 ))]
291 if bytes.len() <= SSO_BUFFER_SIZE {
292 let mut buffer = [0u8; SSO_BUFFER_SIZE];
293 buffer[..bytes.len()].copy_from_slice(bytes);
294 return ArcPayload::Small(buffer, bytes.len() as LengthType);
295 }
296
297 ArcPayload::Large {
298 data: Arc::from(bytes),
299 start: 0,
300 length: bytes.len(),
301 }
302 }
303}
304
305impl IntoPayload for String {
307 fn into_payload(self) -> ArcPayload {
308 let bytes = self.as_bytes();
309
310 #[cfg(any(
311 feature = "sso-min-32bit",
312 feature = "sso-min-64bit",
313 feature = "sso-lv10",
314 feature = "sso-lv20"
315 ))]
316 if bytes.len() <= SSO_BUFFER_SIZE {
317 let mut buffer = [0u8; SSO_BUFFER_SIZE];
318 buffer[..bytes.len()].copy_from_slice(bytes);
319 return ArcPayload::Small(buffer, bytes.len() as LengthType);
320 }
321
322 ArcPayload::Large {
323 data: Arc::from(bytes),
324 start: 0,
325 length: bytes.len(),
326 }
327 }
328}
329
330impl IntoPayload for &[u8] {
332 fn into_payload(self) -> ArcPayload {
333 #[cfg(any(
334 feature = "sso-min-32bit",
335 feature = "sso-min-64bit",
336 feature = "sso-lv10",
337 feature = "sso-lv20"
338 ))]
339 if self.len() <= SSO_BUFFER_SIZE {
340 let mut buffer = [0u8; SSO_BUFFER_SIZE];
341 buffer[..self.len()].copy_from_slice(self);
342 return ArcPayload::Small(buffer, self.len() as LengthType);
343 }
344
345 ArcPayload::Large {
346 data: Arc::from(self),
347 start: 0,
348 length: self.len(),
349 }
350 }
351}
352
353impl IntoPayload for Vec<u8> {
355 fn into_payload(self) -> ArcPayload {
356 #[cfg(any(
357 feature = "sso-min-32bit",
358 feature = "sso-min-64bit",
359 feature = "sso-lv10",
360 feature = "sso-lv20"
361 ))]
362 if self.len() <= SSO_BUFFER_SIZE {
363 let mut buffer = [0u8; SSO_BUFFER_SIZE];
364 buffer[..self.len()].copy_from_slice(&self);
365 return ArcPayload::Small(buffer, self.len() as LengthType);
366 }
367
368 let len = self.len();
369 ArcPayload::Large {
370 data: Arc::from(self),
371 start: 0,
372 length: len,
373 }
374 }
375}
376
377impl IntoPayload for &Vec<u8> {
379 fn into_payload(self) -> ArcPayload {
380 let slice: &[u8] = self.as_slice();
381
382 #[cfg(any(
383 feature = "sso-min-32bit",
384 feature = "sso-min-64bit",
385 feature = "sso-lv10",
386 feature = "sso-lv20"
387 ))]
388 if slice.len() <= SSO_BUFFER_SIZE {
389 let mut buffer = [0u8; SSO_BUFFER_SIZE];
390 buffer[..slice.len()].copy_from_slice(slice);
391 return ArcPayload::Small(buffer, slice.len() as LengthType);
392 }
393
394 ArcPayload::Large {
395 data: Arc::from(slice),
396 start: 0,
397 length: slice.len(),
398 }
399 }
400}
401
402impl<const N: usize> IntoPayload for &[u8; N] {
404 fn into_payload(self) -> ArcPayload {
405 let slice: &[u8] = self.as_slice();
406
407 #[cfg(any(
408 feature = "sso-min-32bit",
409 feature = "sso-min-64bit",
410 feature = "sso-lv10",
411 feature = "sso-lv20"
412 ))]
413 if slice.len() <= SSO_BUFFER_SIZE {
414 let mut buffer = [0u8; SSO_BUFFER_SIZE];
415 buffer[..slice.len()].copy_from_slice(slice);
416 return ArcPayload::Small(buffer, slice.len() as LengthType);
417 }
418
419 ArcPayload::Large {
420 data: Arc::from(slice),
421 start: 0,
422 length: slice.len(),
423 }
424 }
425}
426
427impl IntoPayload for Arc<[u8]> {
429 fn into_payload(self) -> ArcPayload {
430 let len = self.len();
431
432 #[cfg(any(
433 feature = "sso-min-32bit",
434 feature = "sso-min-64bit",
435 feature = "sso-lv10",
436 feature = "sso-lv20"
437 ))]
438 if len <= SSO_BUFFER_SIZE {
439 let mut buffer = [0u8; SSO_BUFFER_SIZE];
440 buffer[..len].copy_from_slice(&self);
441 return ArcPayload::Small(buffer, len as LengthType);
442 }
443
444 ArcPayload::Large {
445 data: self,
446 start: 0,
447 length: len,
448 }
449 }
450}
451
452impl IntoPayload for () {
454 fn into_payload(self) -> ArcPayload {
455 ArcPayload::default() }
457}
458
459impl IntoPayload for ArcPayload {
461 fn into_payload(self) -> ArcPayload {
462 self
463 }
464}
465
466#[cfg(test)]
467mod tests {
468 use super::*;
469
470 #[test]
471 fn test_empty_payload() {
472 let payload = ArcPayload::default();
473 assert_eq!(payload.len(), 0);
474 assert!(payload.is_empty());
475 assert_eq!(payload.as_slice(), &[] as &[u8]);
476 }
477
478 #[test]
479 fn test_small_payload() {
480 let data = b"hello";
481 let payload = data.into_payload();
482 assert_eq!(payload.len(), 5);
483 assert!(!payload.is_empty());
484 assert_eq!(payload.as_slice(), b"hello");
485 }
486
487 #[test]
488 fn test_payload_variants() {
489 let small_data = b"small";
491 let payload = small_data.into_payload();
492
493 #[cfg(any(
494 feature = "sso-min-32bit",
495 feature = "sso-min-64bit",
496 feature = "sso-lv10",
497 feature = "sso-lv20"
498 ))]
499 assert!(matches!(payload, ArcPayload::Small(_, _)));
500
501 #[cfg(not(any(
502 feature = "sso-min-32bit",
503 feature = "sso-min-64bit",
504 feature = "sso-lv10",
505 feature = "sso-lv20"
506 )))]
507 assert!(matches!(payload, ArcPayload::Large { .. }));
508
509 let medium_data = vec![0u8; 200]; let _payload = medium_data.into_payload();
512
513 #[cfg(feature = "sso-lv20")]
515 assert!(matches!(_payload, ArcPayload::Small(_, _)));
516
517 #[cfg(all(
519 any(
520 feature = "sso-min-32bit",
521 feature = "sso-min-64bit",
522 feature = "sso-lv10"
523 ),
524 not(feature = "sso-lv20")
525 ))]
526 assert!(matches!(_payload, ArcPayload::Large { .. }));
527
528 let very_large_data = b"This is a very long payload that exceeds even the largest SSO buffer size of 255 bytes. It should definitely be stored in the Large variant regardless of which SSO feature flags are enabled. This ensures consistent behavior across all configurations and provides a reliable test case.";
530 let payload = very_large_data.into_payload();
531 assert!(matches!(payload, ArcPayload::Large { .. }));
532 }
533
534 #[test]
535 fn test_arc_data_access() {
536 let small_data = b"test";
537 let small_payload = small_data.into_payload();
538
539 let very_large_data = b"This is a very long payload that exceeds even the largest SSO buffer size of 255 bytes. It should definitely be stored in the Large variant regardless of which SSO feature flags are enabled. This ensures consistent behavior across all configurations and provides a reliable test case for arc_data access.";
541 let large_payload = very_large_data.into_payload();
542
543 #[cfg(any(
545 feature = "sso-min-32bit",
546 feature = "sso-min-64bit",
547 feature = "sso-lv10",
548 feature = "sso-lv20"
549 ))]
550 if let ArcPayload::Small(_, _) = small_payload {
551 assert!(small_payload.arc_data().is_none());
552 }
553
554 #[cfg(not(any(
556 feature = "sso-min-32bit",
557 feature = "sso-min-64bit",
558 feature = "sso-lv10",
559 feature = "sso-lv20"
560 )))]
561 assert!(small_payload.arc_data().is_some());
562
563 assert!(large_payload.arc_data().is_some());
565 }
566
567 #[test]
568 fn test_into_payload_implementations() {
569 let str_payload = "hello".into_payload();
571 assert_eq!(str_payload.as_slice(), b"hello");
572
573 let string_payload = String::from("world").into_payload();
574 assert_eq!(string_payload.as_slice(), b"world");
575
576 let vec_payload = vec![1, 2, 3, 4].into_payload();
577 assert_eq!(vec_payload.as_slice(), &[1, 2, 3, 4]);
578
579 let arr_payload = (&[5, 6, 7, 8]).into_payload();
580 assert_eq!(arr_payload.as_slice(), &[5, 6, 7, 8]);
581
582 let unit_payload = ().into_payload();
583 assert!(unit_payload.is_empty());
584 }
585}