1use serde::{de::DeserializeOwned, Deserialize, Serialize};
6use std::{
7 borrow::{Borrow, Cow},
8 ffi::{CStr, OsStr},
9 fmt,
10 hash::Hash,
11 ops::{Add, Deref},
12 path::Path,
13 sync::Arc,
14};
15
16pub enum Oco<'a, T: ?Sized + ToOwned + 'a> {
27 Borrowed(&'a T),
29 Counted(Arc<T>),
31 Owned(<T as ToOwned>::Owned),
33}
34
35impl<'a, T: ?Sized + ToOwned> Oco<'a, T> {
36 pub fn into_owned(self) -> <T as ToOwned>::Owned {
38 match self {
39 Oco::Borrowed(v) => v.to_owned(),
40 Oco::Counted(v) => v.as_ref().to_owned(),
41 Oco::Owned(v) => v,
42 }
43 }
44
45 pub const fn is_borrowed(&self) -> bool {
55 matches!(self, Oco::Borrowed(_))
56 }
57
58 pub const fn is_counted(&self) -> bool {
68 matches!(self, Oco::Counted(_))
69 }
70
71 pub const fn is_owned(&self) -> bool {
81 matches!(self, Oco::Owned(_))
82 }
83}
84
85impl<T: ?Sized + ToOwned> Deref for Oco<'_, T> {
86 type Target = T;
87
88 fn deref(&self) -> &T {
89 match self {
90 Oco::Borrowed(v) => v,
91 Oco::Owned(v) => v.borrow(),
92 Oco::Counted(v) => v,
93 }
94 }
95}
96
97impl<T: ?Sized + ToOwned> Borrow<T> for Oco<'_, T> {
98 #[inline(always)]
99 fn borrow(&self) -> &T {
100 self.deref()
101 }
102}
103
104impl<T: ?Sized + ToOwned> AsRef<T> for Oco<'_, T> {
105 #[inline(always)]
106 fn as_ref(&self) -> &T {
107 self.deref()
108 }
109}
110
111impl AsRef<Path> for Oco<'_, str> {
112 #[inline(always)]
113 fn as_ref(&self) -> &Path {
114 self.as_str().as_ref()
115 }
116}
117
118impl AsRef<Path> for Oco<'_, OsStr> {
119 #[inline(always)]
120 fn as_ref(&self) -> &Path {
121 self.as_os_str().as_ref()
122 }
123}
124
125impl Oco<'_, str> {
130 #[inline(always)]
139 pub fn as_str(&self) -> &str {
140 self
141 }
142}
143
144impl Oco<'_, CStr> {
145 #[inline(always)]
157 pub fn as_c_str(&self) -> &CStr {
158 self
159 }
160}
161
162impl Oco<'_, OsStr> {
163 #[inline(always)]
174 pub fn as_os_str(&self) -> &OsStr {
175 self
176 }
177}
178
179impl Oco<'_, Path> {
180 #[inline(always)]
191 pub fn as_path(&self) -> &Path {
192 self
193 }
194}
195
196impl<T> Oco<'_, [T]>
197where
198 [T]: ToOwned,
199{
200 #[inline(always)]
209 pub fn as_slice(&self) -> &[T] {
210 self
211 }
212}
213
214impl<'a, T> Clone for Oco<'a, T>
215where
216 T: ?Sized + ToOwned + 'a,
217 for<'b> Arc<T>: From<&'b T>,
218{
219 fn clone(&self) -> Self {
240 match self {
241 Self::Borrowed(v) => Self::Borrowed(v),
242 Self::Counted(v) => Self::Counted(Arc::clone(v)),
243 Self::Owned(v) => Self::Counted(Arc::from(v.borrow())),
244 }
245 }
246}
247
248impl<'a, T> Oco<'a, T>
249where
250 T: ?Sized + ToOwned + 'a,
251 for<'b> Arc<T>: From<&'b T>,
252{
253 pub fn clone_inplace(&mut self) -> Self {
265 match &*self {
266 Self::Borrowed(v) => Self::Borrowed(v),
267 Self::Counted(v) => Self::Counted(Arc::clone(v)),
268 Self::Owned(v) => {
269 let rc = Arc::from(v.borrow());
270 *self = Self::Counted(rc.clone());
271 Self::Counted(rc)
272 }
273 }
274 }
275
276 pub fn upgrade_inplace(&mut self) {
288 if let Self::Owned(v) = &*self {
289 let rc = Arc::from(v.borrow());
290 *self = Self::Counted(rc);
291 }
292 }
293}
294
295impl<T: ?Sized> Default for Oco<'_, T>
296where
297 T: ToOwned,
298 T::Owned: Default,
299{
300 fn default() -> Self {
301 Oco::Owned(T::Owned::default())
302 }
303}
304
305impl<'a, 'b, A: ?Sized, B: ?Sized> PartialEq<Oco<'b, B>> for Oco<'a, A>
306where
307 A: PartialEq<B>,
308 A: ToOwned,
309 B: ToOwned,
310{
311 fn eq(&self, other: &Oco<'b, B>) -> bool {
312 **self == **other
313 }
314}
315
316impl<T: ?Sized + ToOwned + Eq> Eq for Oco<'_, T> {}
317
318impl<'a, 'b, A: ?Sized, B: ?Sized> PartialOrd<Oco<'b, B>> for Oco<'a, A>
319where
320 A: PartialOrd<B>,
321 A: ToOwned,
322 B: ToOwned,
323{
324 fn partial_cmp(&self, other: &Oco<'b, B>) -> Option<std::cmp::Ordering> {
325 (**self).partial_cmp(&**other)
326 }
327}
328
329impl<T: ?Sized + Ord> Ord for Oco<'_, T>
330where
331 T: ToOwned,
332{
333 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
334 (**self).cmp(&**other)
335 }
336}
337
338impl<T: ?Sized + Hash> Hash for Oco<'_, T>
339where
340 T: ToOwned,
341{
342 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
343 (**self).hash(state)
344 }
345}
346
347impl<T: ?Sized + fmt::Debug> fmt::Debug for Oco<'_, T>
348where
349 T: ToOwned,
350{
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 (**self).fmt(f)
353 }
354}
355
356impl<T: ?Sized + fmt::Display> fmt::Display for Oco<'_, T>
357where
358 T: ToOwned,
359{
360 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361 (**self).fmt(f)
362 }
363}
364
365impl<'a, T: ?Sized> From<&'a T> for Oco<'a, T>
366where
367 T: ToOwned,
368{
369 fn from(v: &'a T) -> Self {
370 Oco::Borrowed(v)
371 }
372}
373
374impl<'a, T: ?Sized> From<Cow<'a, T>> for Oco<'a, T>
375where
376 T: ToOwned,
377{
378 fn from(v: Cow<'a, T>) -> Self {
379 match v {
380 Cow::Borrowed(v) => Oco::Borrowed(v),
381 Cow::Owned(v) => Oco::Owned(v),
382 }
383 }
384}
385
386impl<'a, T: ?Sized> From<Oco<'a, T>> for Cow<'a, T>
387where
388 T: ToOwned,
389{
390 fn from(value: Oco<'a, T>) -> Self {
391 match value {
392 Oco::Borrowed(v) => Cow::Borrowed(v),
393 Oco::Owned(v) => Cow::Owned(v),
394 Oco::Counted(v) => Cow::Owned(v.as_ref().to_owned()),
395 }
396 }
397}
398
399impl<T: ?Sized> From<Arc<T>> for Oco<'_, T>
400where
401 T: ToOwned,
402{
403 fn from(v: Arc<T>) -> Self {
404 Oco::Counted(v)
405 }
406}
407
408impl<T: ?Sized> From<Box<T>> for Oco<'_, T>
409where
410 T: ToOwned,
411{
412 fn from(v: Box<T>) -> Self {
413 Oco::Counted(v.into())
414 }
415}
416
417impl From<String> for Oco<'_, str> {
418 fn from(v: String) -> Self {
419 Oco::Owned(v)
420 }
421}
422
423impl From<Oco<'_, str>> for String {
424 fn from(v: Oco<'_, str>) -> Self {
425 match v {
426 Oco::Borrowed(v) => v.to_owned(),
427 Oco::Counted(v) => v.as_ref().to_owned(),
428 Oco::Owned(v) => v,
429 }
430 }
431}
432
433impl<T> From<Vec<T>> for Oco<'_, [T]>
434where
435 [T]: ToOwned<Owned = Vec<T>>,
436{
437 fn from(v: Vec<T>) -> Self {
438 Oco::Owned(v)
439 }
440}
441
442impl<'a, T, const N: usize> From<&'a [T; N]> for Oco<'a, [T]>
443where
444 [T]: ToOwned,
445{
446 fn from(v: &'a [T; N]) -> Self {
447 Oco::Borrowed(v)
448 }
449}
450
451impl<'a> From<Oco<'a, str>> for Oco<'a, [u8]> {
452 fn from(v: Oco<'a, str>) -> Self {
453 match v {
454 Oco::Borrowed(v) => Oco::Borrowed(v.as_bytes()),
455 Oco::Owned(v) => Oco::Owned(v.into_bytes()),
456 Oco::Counted(v) => Oco::Counted(v.into()),
457 }
458 }
459}
460
461#[derive(Debug, Clone, thiserror::Error)]
464#[error("invalid utf-8 sequence: {_0}")]
465pub enum FromUtf8Error {
466 #[error("{_0}")]
469 StrFromBytes(
470 #[source]
471 #[from]
472 std::str::Utf8Error,
473 ),
474 #[error("{_0}")]
476 StringFromBytes(
477 #[source]
478 #[from]
479 std::string::FromUtf8Error,
480 ),
481}
482
483macro_rules! impl_slice_eq {
484 ([$($g:tt)*] $((where $($w:tt)+))?, $lhs:ty, $rhs: ty) => {
485 impl<$($g)*> PartialEq<$rhs> for $lhs
486 $(where
487 $($w)*)?
488 {
489 #[inline]
490 fn eq(&self, other: &$rhs) -> bool {
491 PartialEq::eq(&self[..], &other[..])
492 }
493 }
494
495 impl<$($g)*> PartialEq<$lhs> for $rhs
496 $(where
497 $($w)*)?
498 {
499 #[inline]
500 fn eq(&self, other: &$lhs) -> bool {
501 PartialEq::eq(&self[..], &other[..])
502 }
503 }
504 };
505}
506
507impl_slice_eq!([], Oco<'_, str>, str);
508impl_slice_eq!(['a, 'b], Oco<'a, str>, &'b str);
509impl_slice_eq!([], Oco<'_, str>, String);
510impl_slice_eq!(['a, 'b], Oco<'a, str>, Cow<'b, str>);
511
512impl_slice_eq!([T: PartialEq] (where [T]: ToOwned), Oco<'_, [T]>, [T]);
513impl_slice_eq!(['a, 'b, T: PartialEq] (where [T]: ToOwned), Oco<'a, [T]>, &'b [T]);
514impl_slice_eq!([T: PartialEq] (where [T]: ToOwned), Oco<'_, [T]>, Vec<T>);
515impl_slice_eq!(['a, 'b, T: PartialEq] (where [T]: ToOwned), Oco<'a, [T]>, Cow<'b, [T]>);
516
517impl<'a, 'b> Add<&'b str> for Oco<'a, str> {
518 type Output = Oco<'static, str>;
519
520 fn add(self, rhs: &'b str) -> Self::Output {
521 Oco::Owned(String::from(self) + rhs)
522 }
523}
524
525impl<'a, 'b> Add<Cow<'b, str>> for Oco<'a, str> {
526 type Output = Oco<'static, str>;
527
528 fn add(self, rhs: Cow<'b, str>) -> Self::Output {
529 Oco::Owned(String::from(self) + rhs.as_ref())
530 }
531}
532
533impl<'a, 'b> Add<Oco<'b, str>> for Oco<'a, str> {
534 type Output = Oco<'static, str>;
535
536 fn add(self, rhs: Oco<'b, str>) -> Self::Output {
537 Oco::Owned(String::from(self) + rhs.as_ref())
538 }
539}
540
541impl<'a> FromIterator<Oco<'a, str>> for String {
542 fn from_iter<T: IntoIterator<Item = Oco<'a, str>>>(iter: T) -> Self {
543 iter.into_iter().fold(String::new(), |mut acc, item| {
544 acc.push_str(item.as_ref());
545 acc
546 })
547 }
548}
549
550impl<'a, T> Deserialize<'a> for Oco<'static, T>
551where
552 T: ?Sized + ToOwned + 'a,
553 T::Owned: DeserializeOwned,
554{
555 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
556 where
557 D: serde::Deserializer<'a>,
558 {
559 <T::Owned>::deserialize(deserializer).map(Oco::Owned)
560 }
561}
562
563impl<'a, T> Serialize for Oco<'a, T>
564where
565 T: ?Sized + ToOwned + 'a,
566 for<'b> &'b T: Serialize,
567{
568 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
569 where
570 S: serde::Serializer,
571 {
572 self.as_ref().serialize(serializer)
573 }
574}
575
576#[cfg(test)]
577mod tests {
578 use super::*;
579
580 #[test]
581 fn debug_fmt_should_display_quotes_for_strings() {
582 let s: Oco<str> = Oco::Borrowed("hello");
583 assert_eq!(format!("{:?}", s), "\"hello\"");
584 let s: Oco<str> = Oco::Counted(Arc::from("hello"));
585 assert_eq!(format!("{:?}", s), "\"hello\"");
586 }
587
588 #[test]
589 fn partial_eq_should_compare_str_to_str() {
590 let s: Oco<str> = Oco::Borrowed("hello");
591 assert_eq!(s, "hello");
592 assert_eq!("hello", s);
593 assert_eq!(s, String::from("hello"));
594 assert_eq!(String::from("hello"), s);
595 assert_eq!(s, Cow::from("hello"));
596 assert_eq!(Cow::from("hello"), s);
597 }
598
599 #[test]
600 fn partial_eq_should_compare_slice_to_slice() {
601 let s: Oco<[i32]> = Oco::Borrowed([1, 2, 3].as_slice());
602 assert_eq!(s, [1, 2, 3].as_slice());
603 assert_eq!([1, 2, 3].as_slice(), s);
604 assert_eq!(s, vec![1, 2, 3]);
605 assert_eq!(vec![1, 2, 3], s);
606 assert_eq!(s, Cow::<'_, [i32]>::Borrowed(&[1, 2, 3]));
607 assert_eq!(Cow::<'_, [i32]>::Borrowed(&[1, 2, 3]), s);
608 }
609
610 #[test]
611 fn add_should_concatenate_strings() {
612 let s: Oco<str> = Oco::Borrowed("hello");
613 assert_eq!(s.clone() + " world", "hello world");
614 assert_eq!(s.clone() + Cow::from(" world"), "hello world");
615 assert_eq!(s + Oco::from(" world"), "hello world");
616 }
617
618 #[test]
619 fn as_str_should_return_a_str() {
620 let s: Oco<str> = Oco::Borrowed("hello");
621 assert_eq!(s.as_str(), "hello");
622 let s: Oco<str> = Oco::Counted(Arc::from("hello"));
623 assert_eq!(s.as_str(), "hello");
624 }
625
626 #[test]
627 fn as_slice_should_return_a_slice() {
628 let s: Oco<[i32]> = Oco::Borrowed([1, 2, 3].as_slice());
629 assert_eq!(s.as_slice(), [1, 2, 3].as_slice());
630 let s: Oco<[i32]> = Oco::Counted(Arc::from([1, 2, 3]));
631 assert_eq!(s.as_slice(), [1, 2, 3].as_slice());
632 }
633
634 #[test]
635 fn default_for_str_should_return_an_empty_string() {
636 let s: Oco<str> = Default::default();
637 assert!(s.is_empty());
638 }
639
640 #[test]
641 fn default_for_slice_should_return_an_empty_slice() {
642 let s: Oco<[i32]> = Default::default();
643 assert!(s.is_empty());
644 }
645
646 #[test]
647 fn default_for_any_option_should_return_none() {
648 let s: Oco<Option<i32>> = Default::default();
649 assert!(s.is_none());
650 }
651
652 #[test]
653 fn cloned_owned_string_should_make_counted_str() {
654 let s: Oco<str> = Oco::Owned(String::from("hello"));
655 assert!(s.clone().is_counted());
656 }
657
658 #[test]
659 fn cloned_borrowed_str_should_make_borrowed_str() {
660 let s: Oco<str> = Oco::Borrowed("hello");
661 assert!(s.clone().is_borrowed());
662 }
663
664 #[test]
665 fn cloned_counted_str_should_make_counted_str() {
666 let s: Oco<str> = Oco::Counted(Arc::from("hello"));
667 assert!(s.clone().is_counted());
668 }
669
670 #[test]
671 fn cloned_inplace_owned_string_should_make_counted_str_and_become_counted()
672 {
673 let mut s: Oco<str> = Oco::Owned(String::from("hello"));
674 assert!(s.clone_inplace().is_counted());
675 assert!(s.is_counted());
676 }
677
678 #[test]
679 fn cloned_inplace_borrowed_str_should_make_borrowed_str_and_remain_borrowed(
680 ) {
681 let mut s: Oco<str> = Oco::Borrowed("hello");
682 assert!(s.clone_inplace().is_borrowed());
683 assert!(s.is_borrowed());
684 }
685
686 #[test]
687 fn cloned_inplace_counted_str_should_make_counted_str_and_remain_counted() {
688 let mut s: Oco<str> = Oco::Counted(Arc::from("hello"));
689 assert!(s.clone_inplace().is_counted());
690 assert!(s.is_counted());
691 }
692
693 #[test]
694 fn serialization_works() {
695 let s = serde_json::to_string(&Oco::Borrowed("foo"))
696 .expect("should serialize string");
697 assert_eq!(s, "\"foo\"");
698 }
699
700 #[test]
701 fn deserialization_works() {
702 let s: Oco<str> = serde_json::from_str("\"bar\"")
703 .expect("should deserialize from string");
704 assert_eq!(s, Oco::from(String::from("bar")));
705 }
706}