lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

list_sets.rs (9343B)


      1 #![forbid(unsafe_code)]
      2 
      3 #[cfg(not(feature = "std"))]
      4 use alloc::{
      5     format,
      6     string::{String, ToString},
      7     vec,
      8     vec::Vec,
      9 };
     10 
     11 use radroots_events::kinds::KIND_LISTING;
     12 use radroots_events::list::RadrootsListEntry;
     13 use radroots_events::list_set::RadrootsListSet;
     14 use radroots_events::listing::RadrootsListing;
     15 use radroots_events::plot::RadrootsPlot;
     16 
     17 use crate::d_tag::validate_d_tag;
     18 use crate::error::EventEncodeError;
     19 use crate::plot::encode::plot_address;
     20 
     21 const MEMBER_OF_FARMS: &str = "member_of.farms";
     22 
     23 fn farm_list_set_id(farm_id: &str, suffix: &str) -> Result<String, EventEncodeError> {
     24     let farm_id = farm_id.trim();
     25     if farm_id.is_empty() {
     26         return Err(EventEncodeError::EmptyRequiredField("farm_id"));
     27     }
     28     validate_d_tag(farm_id, "farm_id")?;
     29     Ok(format!("farm:{farm_id}:{suffix}"))
     30 }
     31 
     32 fn list_entries<I, S>(tag: &str, values: I) -> Result<Vec<RadrootsListEntry>, EventEncodeError>
     33 where
     34     I: IntoIterator<Item = S>,
     35     S: AsRef<str>,
     36 {
     37     let mut entries = Vec::new();
     38     for value in values {
     39         let value = value.as_ref().trim();
     40         if value.is_empty() {
     41             return Err(EventEncodeError::EmptyRequiredField("entry.values"));
     42         }
     43         entries.push(RadrootsListEntry {
     44             tag: tag.to_string(),
     45             values: vec![value.to_string()],
     46         });
     47     }
     48     Ok(entries)
     49 }
     50 
     51 pub fn farm_members_list_set<I, S>(
     52     farm_id: &str,
     53     members: I,
     54 ) -> Result<RadrootsListSet, EventEncodeError>
     55 where
     56     I: IntoIterator<Item = S>,
     57     S: AsRef<str>,
     58 {
     59     Ok(RadrootsListSet {
     60         d_tag: farm_list_set_id(farm_id, "members")?,
     61         content: String::new(),
     62         entries: list_entries("p", members)?,
     63         title: None,
     64         description: None,
     65         image: None,
     66     })
     67 }
     68 
     69 pub fn farm_owners_list_set<I, S>(
     70     farm_id: &str,
     71     owners: I,
     72 ) -> Result<RadrootsListSet, EventEncodeError>
     73 where
     74     I: IntoIterator<Item = S>,
     75     S: AsRef<str>,
     76 {
     77     Ok(RadrootsListSet {
     78         d_tag: farm_list_set_id(farm_id, "members.owners")?,
     79         content: String::new(),
     80         entries: list_entries("p", owners)?,
     81         title: None,
     82         description: None,
     83         image: None,
     84     })
     85 }
     86 
     87 pub fn farm_workers_list_set<I, S>(
     88     farm_id: &str,
     89     workers: I,
     90 ) -> Result<RadrootsListSet, EventEncodeError>
     91 where
     92     I: IntoIterator<Item = S>,
     93     S: AsRef<str>,
     94 {
     95     Ok(RadrootsListSet {
     96         d_tag: farm_list_set_id(farm_id, "members.workers")?,
     97         content: String::new(),
     98         entries: list_entries("p", workers)?,
     99         title: None,
    100         description: None,
    101         image: None,
    102     })
    103 }
    104 
    105 pub fn farm_plots_list_set<I, S>(
    106     farm_id: &str,
    107     farm_pubkey: &str,
    108     plot_ids: I,
    109 ) -> Result<RadrootsListSet, EventEncodeError>
    110 where
    111     I: IntoIterator<Item = S>,
    112     S: AsRef<str>,
    113 {
    114     let mut entries = Vec::new();
    115     for plot_id in plot_ids {
    116         let plot_id = plot_id.as_ref();
    117         let address = plot_address(farm_pubkey, plot_id)?;
    118         entries.push(RadrootsListEntry {
    119             tag: "a".to_string(),
    120             values: vec![address],
    121         });
    122     }
    123     Ok(RadrootsListSet {
    124         d_tag: farm_list_set_id(farm_id, "plots")?,
    125         content: String::new(),
    126         entries,
    127         title: None,
    128         description: None,
    129         image: None,
    130     })
    131 }
    132 
    133 pub fn farm_listings_list_set<I, S>(
    134     farm_id: &str,
    135     farm_pubkey: &str,
    136     listing_ids: I,
    137 ) -> Result<RadrootsListSet, EventEncodeError>
    138 where
    139     I: IntoIterator<Item = S>,
    140     S: AsRef<str>,
    141 {
    142     let mut entries = Vec::new();
    143     for listing_id in listing_ids {
    144         let listing_id = listing_id.as_ref().trim();
    145         if listing_id.is_empty() {
    146             return Err(EventEncodeError::EmptyRequiredField("listing_id"));
    147         }
    148         validate_d_tag(listing_id, "listing_id")?;
    149         let mut address = String::new();
    150         address.push_str(&KIND_LISTING.to_string());
    151         address.push(':');
    152         address.push_str(farm_pubkey);
    153         address.push(':');
    154         address.push_str(listing_id);
    155         entries.push(RadrootsListEntry {
    156             tag: "a".to_string(),
    157             values: vec![address],
    158         });
    159     }
    160     Ok(RadrootsListSet {
    161         d_tag: farm_list_set_id(farm_id, "listings")?,
    162         content: String::new(),
    163         entries,
    164         title: None,
    165         description: None,
    166         image: None,
    167     })
    168 }
    169 
    170 pub fn farm_listings_list_set_from_listings<'a, I>(
    171     farm_id: &str,
    172     farm_pubkey: &str,
    173     listings: I,
    174 ) -> Result<RadrootsListSet, EventEncodeError>
    175 where
    176     I: IntoIterator<Item = &'a RadrootsListing>,
    177 {
    178     farm_listings_list_set(
    179         farm_id,
    180         farm_pubkey,
    181         listings.into_iter().map(|listing| listing.d_tag.as_str()),
    182     )
    183 }
    184 
    185 pub fn farm_plots_list_set_from_plots<'a, I>(
    186     farm_id: &str,
    187     farm_pubkey: &str,
    188     plots: I,
    189 ) -> Result<RadrootsListSet, EventEncodeError>
    190 where
    191     I: IntoIterator<Item = &'a RadrootsPlot>,
    192 {
    193     farm_plots_list_set(
    194         farm_id,
    195         farm_pubkey,
    196         plots.into_iter().map(|plot| plot.d_tag.as_str()),
    197     )
    198 }
    199 
    200 pub fn member_of_farms_list_set<I, S>(farm_pubkeys: I) -> Result<RadrootsListSet, EventEncodeError>
    201 where
    202     I: IntoIterator<Item = S>,
    203     S: AsRef<str>,
    204 {
    205     Ok(RadrootsListSet {
    206         d_tag: MEMBER_OF_FARMS.to_string(),
    207         content: String::new(),
    208         entries: list_entries("p", farm_pubkeys)?,
    209         title: None,
    210         description: None,
    211         image: None,
    212     })
    213 }
    214 
    215 #[cfg(test)]
    216 mod tests {
    217     use super::*;
    218     use crate::test_fixtures::FIXTURE_ALICE_PUBLIC_KEY_HEX;
    219 
    220     #[test]
    221     fn farm_list_set_id_validates_farm_id() {
    222         let err = farm_list_set_id(" ", "members").expect_err("expected farm_id error");
    223         assert!(matches!(
    224             err,
    225             EventEncodeError::EmptyRequiredField("farm_id")
    226         ));
    227     }
    228 
    229     #[test]
    230     fn farm_list_set_builders_cover_success_and_error_paths() {
    231         let farm_id = "AAAAAAAAAAAAAAAAAAAAAA";
    232         let farm_pubkey = FIXTURE_ALICE_PUBLIC_KEY_HEX;
    233 
    234         let err = farm_members_list_set("invalid", ["member-a"]).expect_err("invalid farm id");
    235         assert!(matches!(err, EventEncodeError::InvalidField("farm_id")));
    236 
    237         let owners = farm_owners_list_set(farm_id, ["owner-a"]).expect("owners list set");
    238         assert_eq!(owners.d_tag, "farm:AAAAAAAAAAAAAAAAAAAAAA:members.owners");
    239         assert_eq!(owners.entries[0].tag, "p");
    240         let err = farm_owners_list_set("invalid", ["owner-a"]).expect_err("invalid farm id");
    241         assert!(matches!(err, EventEncodeError::InvalidField("farm_id")));
    242         let err = farm_owners_list_set(farm_id, [" "]).expect_err("invalid owner entry");
    243         assert!(matches!(
    244             err,
    245             EventEncodeError::EmptyRequiredField("entry.values")
    246         ));
    247 
    248         let workers = farm_workers_list_set(farm_id, ["worker-a"]).expect("workers list set");
    249         assert_eq!(workers.d_tag, "farm:AAAAAAAAAAAAAAAAAAAAAA:members.workers");
    250         assert_eq!(workers.entries[0].tag, "p");
    251         let err = farm_workers_list_set("invalid", ["worker-a"]).expect_err("invalid farm id");
    252         assert!(matches!(err, EventEncodeError::InvalidField("farm_id")));
    253         let err = farm_workers_list_set(farm_id, [" "]).expect_err("invalid worker entry");
    254         assert!(matches!(
    255             err,
    256             EventEncodeError::EmptyRequiredField("entry.values")
    257         ));
    258 
    259         let plots =
    260             farm_plots_list_set(farm_id, farm_pubkey, ["AAAAAAAAAAAAAAAAAAAAAA"]).expect("plots");
    261         assert_eq!(plots.d_tag, "farm:AAAAAAAAAAAAAAAAAAAAAA:plots");
    262         assert_eq!(plots.entries[0].tag, "a");
    263         let err = farm_plots_list_set("invalid", farm_pubkey, ["AAAAAAAAAAAAAAAAAAAAAA"])
    264             .expect_err("invalid farm id");
    265         assert!(matches!(err, EventEncodeError::InvalidField("farm_id")));
    266         let err =
    267             farm_plots_list_set(farm_id, farm_pubkey, ["invalid"]).expect_err("invalid plot_id");
    268         assert!(matches!(err, EventEncodeError::InvalidField("plot.d_tag")));
    269 
    270         let listings = farm_listings_list_set(farm_id, farm_pubkey, ["AAAAAAAAAAAAAAAAAAAAAA"])
    271             .expect("listings");
    272         assert_eq!(listings.d_tag, "farm:AAAAAAAAAAAAAAAAAAAAAA:listings");
    273         assert_eq!(listings.entries[0].tag, "a");
    274         let err = farm_listings_list_set("invalid", farm_pubkey, ["AAAAAAAAAAAAAAAAAAAAAA"])
    275             .expect_err("invalid farm id");
    276         assert!(matches!(err, EventEncodeError::InvalidField("farm_id")));
    277         let err = farm_listings_list_set(farm_id, farm_pubkey, ["invalid"])
    278             .expect_err("invalid listing_id");
    279         assert!(matches!(err, EventEncodeError::InvalidField("listing_id")));
    280 
    281         let err =
    282             farm_listings_list_set(farm_id, farm_pubkey, [" "]).expect_err("empty listing_id");
    283         assert!(matches!(
    284             err,
    285             EventEncodeError::EmptyRequiredField("listing_id")
    286         ));
    287 
    288         let member_of = member_of_farms_list_set(["farm-pubkey"]).expect("member_of farms");
    289         assert_eq!(member_of.d_tag, "member_of.farms");
    290         assert_eq!(member_of.entries[0].tag, "p");
    291         let err = member_of_farms_list_set([" "]).expect_err("invalid member_of entry");
    292         assert!(matches!(
    293             err,
    294             EventEncodeError::EmptyRequiredField("entry.values")
    295         ));
    296     }
    297 }