lib

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

list_sets.rs (9318B)


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