don't
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(atproto): cleanup did module and expand test coverage

Signed-off-by: tjh <x@tjh.dev>

tjh 6afe7b6c 21bd7e94

+174 -84
+136 -84
crates/atproto/src/did.rs
··· 1 1 //! `ATmosphere` specific DID. 2 2 //! 3 - use core::{borrow, fmt, mem, ops}; 3 + use core::{borrow, fmt, mem, ops, ptr}; 4 + 5 + #[cfg(feature = "serde")] 6 + pub(crate) use serde_impl::DidVisitor; 4 7 5 8 /// A slice of an ATmosphere-specific DID. 6 9 /// ··· 19 16 20 17 impl Did { 21 18 fn new<D: AsRef<str> + ?Sized>(did: &D) -> &Self { 22 - unsafe { &*(std::ptr::from_ref::<str>(did.as_ref()) as *const Self) } 19 + unsafe { &*(ptr::from_ref::<str>(did.as_ref()) as *const Self) } 23 20 } 24 21 25 22 const fn new_boxed(did: Box<str>) -> Box<Self> { ··· 137 134 138 135 impl fmt::Debug for Did { 139 136 #[inline] 140 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 137 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 141 138 fmt::Debug::fmt(&self.inner, f) 142 139 } 143 140 } 144 141 145 142 impl fmt::Display for Did { 146 143 #[inline] 147 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 144 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 148 145 fmt::Display::fmt(&self.inner, f) 149 146 } 150 147 } ··· 173 170 } 174 171 } 175 172 176 - impl TryFrom<&str> for Box<Did> { 177 - type Error = Error; 178 - #[inline] 179 - fn try_from(value: &str) -> Result<Self, Self::Error> { 180 - validate_did(value)?; 181 - Ok(Did::new_boxed(value.to_owned().into_boxed_str())) 182 - } 183 - } 184 - 185 173 impl TryFrom<Box<str>> for Box<Did> { 186 174 type Error = Error; 187 175 #[inline] ··· 197 203 type Err = Error; 198 204 #[inline] 199 205 fn from_str(s: &str) -> Result<Self, Self::Err> { 200 - s.try_into() 206 + validate_did(s)?; 207 + Ok(Did::new_boxed(s.into())) 201 208 } 202 209 } 203 210 ··· 322 327 } 323 328 324 329 impl fmt::Debug for OwnedDid { 325 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 330 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 326 331 fmt::Debug::fmt(&self.inner, f) 327 332 } 328 333 } 329 334 330 335 impl fmt::Display for OwnedDid { 331 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 336 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 332 337 fmt::Display::fmt(&self.inner, f) 333 338 } 334 339 } ··· 407 412 impl From<std::borrow::Cow<'_, Did>> for OwnedDid { 408 413 fn from(value: std::borrow::Cow<'_, Did>) -> Self { 409 414 use std::borrow::Cow; 410 - 411 415 match value { 412 416 Cow::Borrowed(did) => did.to_owned(), 413 417 Cow::Owned(did) => did, 414 418 } 415 - } 416 - } 417 - 418 - #[derive(Hash, PartialEq, Eq, PartialOrd, Ord)] 419 - #[repr(transparent)] 420 - pub struct CowDid<'a>(pub std::borrow::Cow<'a, Did>); 421 - 422 - impl fmt::Display for CowDid<'_> { 423 - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 424 - fmt::Display::fmt(&self.0, f) 425 - } 426 - } 427 - 428 - impl fmt::Debug for CowDid<'_> { 429 - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 430 - fmt::Debug::fmt(&self.0, f) 431 - } 432 - } 433 - 434 - impl ops::Deref for CowDid<'_> { 435 - type Target = Did; 436 - fn deref(&self) -> &Self::Target { 437 - &self.0 438 419 } 439 420 } 440 421 ··· 448 477 449 478 impl_partial_eq!(Box<Did>); 450 479 impl_partial_eq!(OwnedDid); 451 - impl_partial_eq!(CowDid<'_>); 452 480 453 481 #[cfg(feature = "serde")] 454 482 mod serde_impl { 455 483 use std::borrow::Cow; 456 484 457 - use super::{CowDid, Did, OwnedDid}; 485 + use super::{Did, OwnedDid}; 458 486 459 487 #[derive(Default)] 460 - struct DidVisitor<'a>(std::marker::PhantomData<&'a Did>); 488 + pub struct DidVisitor<'a>(std::marker::PhantomData<&'a Did>); 461 489 462 490 impl<'de: 'a, 'a> serde::de::Visitor<'de> for DidVisitor<'a> { 463 491 type Value = Cow<'a, Did>; 464 492 465 493 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { 466 494 formatter.write_str("ATproto DID") 467 - } 468 - 469 - fn visit_string<E>(self, v: String) -> Result<Self::Value, E> 470 - where 471 - E: serde::de::Error, 472 - { 473 - let did = v.try_into().map_err(serde::de::Error::custom)?; 474 - Ok(Cow::Owned(did)) 475 495 } 476 496 477 497 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> ··· 514 552 } 515 553 } 516 554 517 - impl<'de: 'a, 'a> serde::Deserialize<'de> for CowDid<'a> { 518 - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 519 - where 520 - D: serde::Deserializer<'de>, 521 - { 522 - Ok(Self(deserializer.deserialize_str(DidVisitor::default())?)) 523 - } 524 - } 525 - 526 555 macro_rules! impl_serialize { 527 556 ($type:ty) => { 528 557 impl serde::Serialize for $type { ··· 529 576 530 577 impl_serialize!(Did); 531 578 impl_serialize!(OwnedDid); 532 - impl_serialize!(CowDid<'_>); 533 579 } 534 580 535 581 #[cfg(feature = "sqlx")] ··· 593 641 594 642 #[cfg(test)] 595 643 mod tests { 596 - use super::{CowDid, Did, Error, OwnedDid}; 644 + use super::{Did, Error, OwnedDid}; 597 645 598 646 /// An example DID. 599 647 const EXAMPLE_DID: &str = "did:plc:65gha4t3avpfpzmvpbwovss7"; ··· 671 719 } 672 720 673 721 #[test] 674 - fn can_display_did() { 722 + fn can_display() { 675 723 let did = Did::from_static(EXAMPLE_DID); 676 724 677 725 assert_eq!(format!("{did}"), EXAMPLE_DID); ··· 702 750 #[test] 703 751 fn can_convert_box_str_inplace() { 704 752 let boxed_str = String::from(EXAMPLE_DID).into_boxed_str(); 705 - let ptr = boxed_str.as_ptr() as usize; 753 + let str_ptr = boxed_str.as_ptr() as usize; 706 754 707 755 let did: Box<Did> = boxed_str.try_into().unwrap(); 756 + let did_ptr = did.as_ptr() as usize; 708 757 assert_eq!( 709 - ptr, 710 - did.as_ptr() as usize, 758 + str_ptr, did_ptr, 711 759 "Boxed DID should point to same memory as boxed str" 712 760 ); 761 + 762 + let bs: Box<str> = did.into(); 763 + assert_eq!(did_ptr, bs.as_ptr() as usize); 713 764 } 714 765 715 766 #[test] ··· 730 775 731 776 #[test] 732 777 #[cfg(feature = "serde")] 733 - fn can_deserialize_borrowed() { 734 - #[derive(serde::Deserialize)] 778 + fn can_serde_borrowed() { 779 + #[derive(serde::Deserialize, serde::Serialize)] 735 780 struct Test<'a> { 736 781 #[serde(borrow)] 737 782 did: &'a Did, 738 783 } 739 784 740 - let json = serde_json::to_string(&serde_json::json!({"did":EXAMPLE_DID})).unwrap(); 785 + let test = Test { 786 + did: Did::from_static(EXAMPLE_DID), 787 + }; 788 + 789 + let json = serde_json::to_string(&test).unwrap(); 741 790 let test: Test = serde_json::from_str(&json).unwrap(); 742 791 assert_eq!(test.did, EXAMPLE_DID); 743 792 assert_eq!(EXAMPLE_DID, test.did); ··· 749 790 750 791 #[test] 751 792 #[cfg(feature = "serde")] 752 - fn can_deserialize_owned() { 753 - #[derive(serde::Deserialize)] 793 + fn can_serde_owned() { 794 + #[derive(serde::Deserialize, serde::Serialize)] 754 795 struct Test { 755 796 did: OwnedDid, 756 797 } 757 798 758 - let json = serde_json::to_string(&serde_json::json!({"did":EXAMPLE_DID})).unwrap(); 799 + let test = Test { 800 + did: OwnedDid::from_static(EXAMPLE_DID), 801 + }; 802 + 803 + let json = serde_json::to_string(&test).unwrap(); 759 804 let test: Test = serde_json::from_str(&json).unwrap(); 805 + 806 + assert_eq!(test.did, EXAMPLE_DID); 807 + assert_eq!(EXAMPLE_DID, test.did); 808 + 809 + let reader = std::io::Cursor::new(json); 810 + let test: Test = serde_json::from_reader(reader).unwrap(); 811 + 760 812 assert_eq!(test.did, EXAMPLE_DID); 761 813 assert_eq!(EXAMPLE_DID, test.did); 762 814 } 763 815 764 816 #[test] 765 817 #[cfg(feature = "serde")] 766 - fn can_deserialized_boxed() { 767 - #[derive(serde::Deserialize)] 818 + fn can_serde_boxed() { 819 + #[derive(serde::Deserialize, serde::Serialize)] 768 820 struct Test { 769 821 did: Box<Did>, 770 822 } 771 823 772 - let json = serde_json::to_string(&serde_json::json!({"did":EXAMPLE_DID})).unwrap(); 824 + let test = Test { 825 + did: Did::parse(EXAMPLE_DID).unwrap().into_boxed(), 826 + }; 827 + 828 + let json = serde_json::to_string(&test).unwrap(); 773 829 let test: Test = serde_json::from_str(&json).unwrap(); 830 + 831 + assert_eq!(test.did, EXAMPLE_DID); 832 + assert_eq!(EXAMPLE_DID, test.did); 833 + 834 + let reader = std::io::Cursor::new(json); 835 + let test: Test = serde_json::from_reader(reader).unwrap(); 836 + 774 837 assert_eq!(test.did, EXAMPLE_DID); 775 838 assert_eq!(EXAMPLE_DID, test.did); 776 839 } 777 840 778 841 #[test] 779 842 #[cfg(feature = "serde")] 780 - fn can_deserialized_cow() { 781 - #[derive(serde::Deserialize)] 843 + fn can_serde_cow_borrowed_static() { 844 + use std::borrow::Cow; 845 + 846 + #[derive(serde::Deserialize, serde::Serialize)] 782 847 struct Test<'a> { 783 - #[serde(borrow)] 784 - did: CowDid<'a>, 848 + #[serde(borrow, with = "crate::serde::cowdid")] 849 + did: Cow<'a, Did>, 785 850 } 786 851 787 - let json = serde_json::to_string(&serde_json::json!({"did":EXAMPLE_DID})).unwrap(); 788 - let test: Test = serde_json::from_str(&json).unwrap(); 789 - assert_eq!(test.did, EXAMPLE_DID); 790 - assert_eq!(EXAMPLE_DID, test.did); 852 + let test = Test { 853 + did: Cow::Borrowed(Did::from_static(EXAMPLE_DID)), 854 + }; 791 855 792 - assert!(matches!(test.did.0, std::borrow::Cow::Borrowed(_))); 856 + let json = serde_json::to_string(&test).unwrap(); 857 + let test: Test = serde_json::from_str(&json).unwrap(); 858 + assert!(matches!(test.did, Cow::Borrowed(_))); 859 + 860 + assert_eq!(test.did.as_str(), EXAMPLE_DID); 861 + assert_eq!(EXAMPLE_DID, test.did.as_str()); 862 + } 863 + 864 + #[test] 865 + #[cfg(feature = "serde")] 866 + fn can_serde_cow_borrowed() { 867 + use std::borrow::Cow; 868 + 869 + #[derive(serde::Deserialize, serde::Serialize)] 870 + struct Test<'a> { 871 + #[serde(borrow, with = "crate::serde::cowdid")] 872 + did: Cow<'a, Did>, 873 + } 874 + 875 + let did_str = String::from(EXAMPLE_DID); 876 + let did = Did::parse(&did_str).unwrap(); 877 + let test = Test { 878 + did: Cow::Borrowed(did), 879 + }; 880 + 881 + let json = serde_json::to_string(&test).unwrap(); 882 + let test: Test = serde_json::from_str(&json).unwrap(); 883 + assert!(matches!(test.did, Cow::Borrowed(_))); 884 + 885 + assert_eq!(test.did.as_str(), EXAMPLE_DID); 886 + assert_eq!(EXAMPLE_DID, test.did.as_str()); 887 + } 888 + 889 + #[test] 890 + #[cfg(feature = "serde")] 891 + fn can_serde_cow_owned() { 892 + use std::borrow::Cow; 893 + 894 + #[derive(serde::Deserialize, serde::Serialize)] 895 + struct Test<'a> { 896 + #[serde(borrow, with = "crate::serde::cowdid")] 897 + did: Cow<'a, Did>, 898 + } 899 + 900 + let did = OwnedDid::parse(EXAMPLE_DID).unwrap(); 901 + let test = Test { 902 + did: Cow::Owned(did), 903 + }; 904 + 905 + let json = serde_json::to_string(&test).unwrap(); 906 + let test: Test = serde_json::from_str(&json).unwrap(); 907 + assert!(matches!(test.did, std::borrow::Cow::Borrowed(_))); 908 + 909 + assert_eq!(test.did.as_str(), EXAMPLE_DID); 910 + assert_eq!(EXAMPLE_DID, test.did.as_str()); 911 + } 912 + 913 + #[test] 914 + fn can_convert_cow() { 915 + use std::borrow::Cow; 916 + 917 + let did = OwnedDid::from_static(EXAMPLE_DID); 918 + let cow: Cow<_> = did.into(); 919 + assert!(matches!(cow, Cow::Owned(_))); 920 + 921 + // Convert back to owned. 922 + let _: OwnedDid = cow.into(); 923 + 924 + let did = Did::from_static(EXAMPLE_DID); 925 + let cow: Cow<_> = did.into(); 926 + assert!(matches!(cow, Cow::Borrowed(_))); 793 927 } 794 928 795 929 #[test]
+3
crates/atproto/src/lib.rs
··· 10 10 pub use did::Did; 11 11 pub use handle::Handle; 12 12 pub use nsid::Nsid; 13 + 14 + #[cfg(feature = "serde")] 15 + pub mod serde;
+35
crates/atproto/src/serde.rs
··· 1 + /// Helper module to correctly serialize and deserialize a `Cow<'_, Did>` with serde. 2 + /// 3 + /// # Example 4 + /// 5 + /// ```rust,no_run 6 + /// use atproto::Did; 7 + /// 8 + /// #[derive(Debug, serde::Deserialize, serde::Serialize)] 9 + /// struct SomeStruct<'a> { 10 + /// #[serde(borrow, with = "atproto::serde::cowdid")] 11 + /// did: Cow<'a, Did>, 12 + /// } 13 + /// ``` 14 + /// 15 + pub mod cowdid { 16 + use std::borrow::Cow; 17 + 18 + use serde::{Deserializer, Serializer}; 19 + 20 + use crate::{Did, did::DidVisitor}; 21 + 22 + pub fn deserialize<'a, 'de: 'a, D>(deserializer: D) -> Result<Cow<'a, Did>, D::Error> 23 + where 24 + D: Deserializer<'de>, 25 + { 26 + Ok(deserializer.deserialize_str(DidVisitor::default())?) 27 + } 28 + 29 + pub fn serialize<S>(did: &Cow<'_, Did>, serializer: S) -> Result<S::Ok, S::Error> 30 + where 31 + S: Serializer, 32 + { 33 + serializer.serialize_str(did) 34 + } 35 + }