1use crate::{encode::encode, decode::decode_unchecked, Error};
12use std::fmt;
13
14#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
17pub struct DecSixbit {
18 pub(crate) len: usize,
20 pub(crate) bytes: Vec<u8>,
22}
23
24impl DecSixbit {
25 const TRAILING_SPACE_MARKER: u8 = 0b11;
27
28 #[inline(always)]
46 pub fn new(str: &str) -> Result<Self, Error> {
47 let (mut bytes, len) = encode(str)?;
48 if len % 4 == 0 && len != 0 && (bytes.last().unwrap() & 0b111111) == 0 {
50 bytes.push(Self::TRAILING_SPACE_MARKER);
51 }
52 Ok(Self { bytes, len })
53 }
54
55 #[inline(always)]
69 pub fn as_bytes(&self) -> &[u8] {
70 &self.bytes
71 }
72
73 #[inline(always)]
87 pub fn len(&self) -> usize {
88 self.len
89 }
90
91 #[inline(always)]
105 pub fn is_empty(&self) -> bool {
106 self.len == 0
107 }
108
109 #[inline(always)]
118 pub fn try_from_slice(bytes: &[u8]) -> Result<Self, Error> {
119 let num_full_blocks = bytes.len() / 3;
120 let num_remain_bytes = bytes.len() % 3;
121
122 let len = match num_remain_bytes {
123 0 => num_full_blocks * 4,
124 1 => {
125 if bytes.last().unwrap() == &Self::TRAILING_SPACE_MARKER {
126 num_full_blocks * 4
127 } else {
128 num_full_blocks * 4 + 1
129 }
130 },
131 2 => num_full_blocks * 4 + 2,
132 _ => unreachable!(),
133 };
134 Ok(Self {
135 len,
136 bytes: bytes.to_vec(),
137 })
138 }
139
140 #[inline(always)]
148 pub fn from_slice(bytes: &[u8]) -> Self {
149 Self::try_from_slice(bytes).unwrap()
150 }
151
152 pub fn get(&self, index: usize) -> Option<char> {
170 self.to_string().chars().nth(index)
171 }
172
173 pub fn starts_with<P: AsRef<str>>(&self, prefix: P) -> bool {
191 self.to_string().starts_with(prefix.as_ref())
192 }
193
194 pub fn ends_with<P: AsRef<str>>(&self, suffix: P) -> bool {
212 self.to_string().ends_with(suffix.as_ref())
213 }
214
215 pub fn contains<P: AsRef<str>>(&self, substring: P) -> bool {
233 self.to_string().contains(substring.as_ref())
234 }
235}
236
237impl fmt::Display for DecSixbit {
238 #[inline(always)]
239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240 let decoded = decode_unchecked(&self.bytes, self.len);
242 write!(f, "{}", decoded)
243 }
244}
245
246impl std::str::FromStr for DecSixbit {
247 type Err = Error;
248
249 fn from_str(s: &str) -> Result<Self, Self::Err> {
250 Self::new(s)
251 }
252}
253
254impl TryFrom<&str> for DecSixbit {
255 type Error = Error;
256
257 fn try_from(s: &str) -> Result<Self, Self::Error> {
258 Self::new(s)
259 }
260}
261
262impl TryFrom<&[u8]> for DecSixbit {
263 type Error = Error;
264
265 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
266 Self::try_from_slice(bytes)
267 }
268}
269
270impl TryFrom<Vec<u8>> for DecSixbit {
271 type Error = Error;
272
273 fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
274 Self::try_from(bytes.as_slice())
275 }
276}
277
278impl TryFrom<&Vec<u8>> for DecSixbit {
279 type Error = Error;
280
281 fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
282 Self::try_from(bytes.as_slice())
283 }
284}
285
286impl AsRef<[u8]> for DecSixbit {
287 fn as_ref(&self) -> &[u8] {
288 self.as_bytes()
289 }
290}
291
292impl serde::Serialize for DecSixbit {
293 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
294 if serializer.is_human_readable() {
295 self.to_string().serialize(serializer)
296 } else {
297 (&self.len, &self.bytes).serialize(serializer)
298 }
299 }
300}
301
302mod deserialize {
303 use super::DecSixbit;
304
305 pub(super) struct DecSixbitVisitor;
306
307 #[allow(clippy::needless_lifetimes)]
308 impl<'de> serde::de::Visitor<'de> for DecSixbitVisitor {
309 type Value = DecSixbit;
310
311 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312 formatter.write_str("bytes or string")
313 }
314
315 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
316 where
317 E: serde::de::Error,
318 {
319 DecSixbit::new(v).map_err(E::custom)
320 }
321 }
322}
323
324impl<'de> serde::Deserialize<'de> for DecSixbit {
325 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<DecSixbit, D::Error> {
326 use serde::de::Error;
327 if deserializer.is_human_readable() {
328 deserializer
329 .deserialize_str(deserialize::DecSixbitVisitor)
330 .map_err(D::Error::custom)
331 } else {
332 let (len, bytes) = <(usize, Vec<u8>)>::deserialize(deserializer)?;
333 Ok(DecSixbit { len, bytes })
334 }
335 }
336}
337
338#[cfg(test)]
339mod tests {
340 use super::DecSixbit;
341 use crate::Error;
342 use std::convert::TryFrom;
343
344 #[test]
345 fn test_new_valid_input() {
346 let input = "HELLO";
347 let sixbit = DecSixbit::new(input).unwrap();
348 assert_eq!(sixbit.len(), input.len());
349 assert_eq!(sixbit.to_string(), input);
350 }
351
352 #[test]
353 fn test_new_empty_string() {
354 let input = "";
355 let sixbit = DecSixbit::new(input).unwrap();
356 assert_eq!(sixbit.len(), 0);
357 assert!(sixbit.is_empty());
358 assert_eq!(sixbit.to_string(), input);
359 }
360
361 #[test]
362 fn test_new_invalid_character() {
363 let input = "HELLO😃";
364 let result = DecSixbit::new(input);
365 assert!(result.is_err());
366 match result {
367 Err(Error::InvalidCharacter { .. }) => (),
368 _ => panic!("Expected InvalidCharacter error"),
369 }
370 }
371
372 #[test]
373 fn test_as_bytes() {
374 let input = "TEST";
375 let sixbit = DecSixbit::new(input).unwrap();
376 let encoded = sixbit.as_bytes();
377 assert!(!encoded.is_empty());
380 assert_eq!(encoded.len(), 3); }
382
383 #[test]
384 fn test_try_from_slice_valid() {
385 let input = "DATA";
386 let sixbit = DecSixbit::new(input).unwrap();
387 let bytes = sixbit.as_bytes();
388 let decoded = DecSixbit::try_from_slice(bytes).unwrap();
389 assert_eq!(sixbit, decoded);
390 }
391
392 #[test]
393 fn test_try_from_slice_with_trailing_marker() {
394 let input = "FOUR";
395 let sixbit = DecSixbit::new(input).unwrap();
396 let mut bytes = sixbit.as_bytes().to_vec();
397 bytes.push(DecSixbit::TRAILING_SPACE_MARKER);
399 let decoded = DecSixbit::try_from_slice(&bytes).unwrap();
400 assert_eq!(decoded.len, sixbit.len);
401 assert_eq!(decoded.bytes, bytes);
402 }
403
404 #[test]
405 fn test_get_valid_index() {
406 let input = "WORLD";
407 let sixbit = DecSixbit::new(input).unwrap();
408 assert_eq!(sixbit.get(0), Some('W'));
409 assert_eq!(sixbit.get(4), Some('D'));
410 }
411
412 #[test]
413 fn test_get_invalid_index() {
414 let input = "WORLD";
415 let sixbit = DecSixbit::new(input).unwrap();
416 assert_eq!(sixbit.get(5), None);
417 }
418
419 #[test]
420 fn test_starts_with() {
421 let sixbit = DecSixbit::new("START").unwrap();
422 assert!(sixbit.starts_with("ST"));
423 assert!(!sixbit.starts_with("TA"));
424 }
425
426 #[test]
427 fn test_ends_with() {
428 let sixbit = DecSixbit::new("ENDING").unwrap();
429 assert!(sixbit.ends_with("ING"));
430 assert!(!sixbit.ends_with("END"));
431 }
432
433 #[test]
434 fn test_contains() {
435 let sixbit = DecSixbit::new("CONTAINS").unwrap();
436 assert!(sixbit.contains("TAI"));
437 assert!(!sixbit.contains("XYZ"));
438 }
439
440 #[test]
441 fn test_display_trait() {
442 let input = "DISPLAY";
443 let sixbit = DecSixbit::new(input).unwrap();
444 let displayed = format!("{}", sixbit);
445 assert_eq!(displayed, input);
446 }
447
448 #[test]
449 fn test_from_str() {
450 let input = "FROM_STR";
451 let sixbit: DecSixbit = input.parse().unwrap();
452 assert_eq!(sixbit.to_string(), input);
453 }
454
455 #[test]
456 fn test_try_from_str_valid() {
457 let input = "TRY_FROM";
458 let sixbit = DecSixbit::try_from(input).unwrap();
459 assert_eq!(sixbit.to_string(), input);
460 }
461
462 #[test]
463 fn test_try_from_str_invalid() {
464 let input = "INVALID😤";
465 let result = DecSixbit::try_from(input);
466 assert!(result.is_err());
467 }
468
469 #[test]
470 fn test_try_from_bytes_valid() {
471 let input = "BYTES";
472 let sixbit = DecSixbit::new(input).unwrap();
473 let bytes = sixbit.as_bytes();
474 let decoded = DecSixbit::try_from(bytes).unwrap();
475 assert_eq!(sixbit, decoded);
476 }
477
478 #[test]
479 fn test_try_from_vec_bytes() {
480 let input = "VEC_BYTES";
481 let sixbit = DecSixbit::new(input).unwrap();
482 let bytes = sixbit.as_bytes().to_vec();
483 let decoded = DecSixbit::try_from(bytes).unwrap();
484 assert_eq!(sixbit, decoded);
485 }
486
487 #[test]
488 fn test_serde_serialize_deserialize_human_readable() {
489 use serde_json;
490
491 let input = "SERIALIZE";
492 let sixbit = DecSixbit::new(input).unwrap();
493 let serialized = serde_json::to_string(&sixbit).unwrap();
494 assert_eq!(serialized, format!("\"{}\"", input));
495
496 let deserialized: DecSixbit = serde_json::from_str(&serialized).unwrap();
497 assert_eq!(sixbit, deserialized);
498 }
499
500 #[test]
501 fn test_serde_serialize_deserialize_binary() {
502 use bincode;
503
504 let input = "BINARY";
505 let sixbit = DecSixbit::new(input).unwrap();
506 let serialized = bincode::serialize(&sixbit).unwrap();
507 let deserialized: DecSixbit = bincode::deserialize(&serialized).unwrap();
508 assert_eq!(sixbit, deserialized);
509 }
510
511 #[test]
512 fn test_is_empty() {
513 let sixbit = DecSixbit::new("").unwrap();
514 assert!(sixbit.is_empty());
515
516 let sixbit = DecSixbit::new("NON_EMPTY").unwrap();
517 assert!(!sixbit.is_empty());
518 }
519
520 #[test]
521 fn test_len() {
522 let input = "LENGTH";
523 let sixbit = DecSixbit::new(input).unwrap();
524 assert_eq!(sixbit.len(), input.len());
525 }
526
527 #[test]
528 fn test_equality() {
529 let input1 = "EQUAL";
530 let input2 = "EQUAL";
531 let sixbit1 = DecSixbit::new(input1).unwrap();
532 let sixbit2 = DecSixbit::new(input2).unwrap();
533 assert_eq!(sixbit1, sixbit2);
534 }
535
536 #[test]
537 fn test_ordering() {
538 let sixbit_a = DecSixbit::new("AAA").unwrap();
539 let sixbit_b = DecSixbit::new("AAB").unwrap();
540 assert!(sixbit_a < sixbit_b);
541 }
542
543 #[test]
544 fn test_hash() {
545 use std::collections::HashSet;
546
547 let input1 = "HASH1";
548 let input2 = "HASH2";
549 let sixbit1 = DecSixbit::new(input1).unwrap();
550 let sixbit2 = DecSixbit::new(input2).unwrap();
551
552 let mut set = HashSet::new();
553 set.insert(sixbit1.clone());
554 set.insert(sixbit2.clone());
555
556 assert!(set.contains(&sixbit1));
557 assert!(set.contains(&sixbit2));
558 }
559}