lib

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

admission.rs (5681B)


      1 #[cfg(not(feature = "std"))]
      2 use alloc::boxed::Box;
      3 
      4 use core::fmt;
      5 
      6 use radroots_event::{
      7     contract::EventContract, envelope::EventEnvelope,
      8     food::availability::RADROOTS_FOOD_AVAILABILITY_CONTRACT_ID,
      9     listing::classified::ClassifiedListingPartition,
     10 };
     11 
     12 use crate::{
     13     food_availability::inbound::{
     14         RadrootsFoodAvailabilityProjectionError, RadrootsFoodAvailabilityProjectionOutcome,
     15         RadrootsInboundFoodAvailabilityProjection, project_verified_food_availability_event,
     16     },
     17     verification::{
     18         RadrootsNip01VerificationError, RadrootsSignatureVerifiedEvent, verify_nip01_event,
     19     },
     20 };
     21 
     22 /// A verified focused FoodAvailability event bound to its tolerant projection.
     23 #[derive(Clone, Debug, PartialEq, Eq)]
     24 pub struct RadrootsAdmittedFoodAvailabilityEvent {
     25     verified_event: RadrootsSignatureVerifiedEvent,
     26     projection: RadrootsInboundFoodAvailabilityProjection,
     27 }
     28 
     29 impl RadrootsAdmittedFoodAvailabilityEvent {
     30     pub fn verified_event(&self) -> &RadrootsSignatureVerifiedEvent {
     31         &self.verified_event
     32     }
     33 
     34     pub fn event(&self) -> &EventEnvelope {
     35         self.verified_event.event()
     36     }
     37 
     38     pub fn projection(&self) -> &RadrootsInboundFoodAvailabilityProjection {
     39         &self.projection
     40     }
     41 
     42     pub fn contract(&self) -> &'static EventContract {
     43         radroots_event::contract::event_contract(RADROOTS_FOOD_AVAILABILITY_CONTRACT_ID)
     44             .expect("FoodAvailability contract ID is registry-owned")
     45     }
     46 
     47     pub fn into_parts(
     48         self,
     49     ) -> (
     50         RadrootsSignatureVerifiedEvent,
     51         RadrootsInboundFoodAvailabilityProjection,
     52     ) {
     53         (self.verified_event, self.projection)
     54     }
     55 }
     56 
     57 /// A verified kind-30402 event excluded from the focused Food profile.
     58 #[derive(Clone, Debug, PartialEq, Eq)]
     59 pub struct RadrootsExcludedClassifiedListingCandidate {
     60     verified_event: RadrootsSignatureVerifiedEvent,
     61     partition: ClassifiedListingPartition,
     62 }
     63 
     64 impl RadrootsExcludedClassifiedListingCandidate {
     65     pub fn verified_event(&self) -> &RadrootsSignatureVerifiedEvent {
     66         &self.verified_event
     67     }
     68 
     69     pub fn event(&self) -> &EventEnvelope {
     70         self.verified_event.event()
     71     }
     72 
     73     pub const fn partition(&self) -> ClassifiedListingPartition {
     74         self.partition
     75     }
     76 
     77     pub fn into_parts(self) -> (RadrootsSignatureVerifiedEvent, ClassifiedListingPartition) {
     78         (self.verified_event, self.partition)
     79     }
     80 }
     81 
     82 #[non_exhaustive]
     83 #[derive(Clone, Debug, PartialEq, Eq)]
     84 pub enum RadrootsFoodAvailabilityAdmissionOutcome {
     85     Admitted(Box<RadrootsAdmittedFoodAvailabilityEvent>),
     86     Excluded(RadrootsExcludedClassifiedListingCandidate),
     87 }
     88 
     89 #[non_exhaustive]
     90 #[derive(Clone, Debug, PartialEq, Eq)]
     91 pub enum RadrootsFoodAvailabilityAdmissionError {
     92     Nip01Verification(RadrootsNip01VerificationError),
     93     Projection(RadrootsFoodAvailabilityProjectionError),
     94 }
     95 
     96 impl RadrootsFoodAvailabilityAdmissionError {
     97     pub const fn code(&self) -> &'static str {
     98         match self {
     99             Self::Nip01Verification(error) => error.code(),
    100             Self::Projection(error) => error.code(),
    101         }
    102     }
    103 }
    104 
    105 impl fmt::Display for RadrootsFoodAvailabilityAdmissionError {
    106     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    107         match self {
    108             Self::Nip01Verification(error) => write!(formatter, "{error}"),
    109             Self::Projection(error) => write!(formatter, "{error}"),
    110         }
    111     }
    112 }
    113 
    114 #[cfg(feature = "std")]
    115 impl std::error::Error for RadrootsFoodAvailabilityAdmissionError {
    116     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
    117         match self {
    118             Self::Nip01Verification(error) => Some(error),
    119             Self::Projection(error) => Some(error),
    120         }
    121     }
    122 }
    123 
    124 impl From<RadrootsNip01VerificationError> for RadrootsFoodAvailabilityAdmissionError {
    125     fn from(value: RadrootsNip01VerificationError) -> Self {
    126         Self::Nip01Verification(value)
    127     }
    128 }
    129 
    130 impl From<RadrootsFoodAvailabilityProjectionError> for RadrootsFoodAvailabilityAdmissionError {
    131     fn from(value: RadrootsFoodAvailabilityProjectionError) -> Self {
    132         Self::Projection(value)
    133     }
    134 }
    135 
    136 /// Admits or explicitly excludes an already verified classified listing.
    137 pub fn admit_verified_food_availability_event(
    138     verified_event: RadrootsSignatureVerifiedEvent,
    139 ) -> Result<RadrootsFoodAvailabilityAdmissionOutcome, RadrootsFoodAvailabilityAdmissionError> {
    140     match project_verified_food_availability_event(&verified_event)? {
    141         RadrootsFoodAvailabilityProjectionOutcome::Focused(projection) => {
    142             Ok(RadrootsFoodAvailabilityAdmissionOutcome::Admitted(
    143                 Box::new(RadrootsAdmittedFoodAvailabilityEvent {
    144                     verified_event,
    145                     projection: *projection,
    146                 }),
    147             ))
    148         }
    149         RadrootsFoodAvailabilityProjectionOutcome::Excluded(partition) => {
    150             debug_assert!(matches!(
    151                 partition,
    152                 ClassifiedListingPartition::OperationalListing
    153                     | ClassifiedListingPartition::GenericNip99
    154             ));
    155             Ok(RadrootsFoodAvailabilityAdmissionOutcome::Excluded(
    156                 RadrootsExcludedClassifiedListingCandidate {
    157                     verified_event,
    158                     partition,
    159                 },
    160             ))
    161         }
    162     }
    163 }
    164 
    165 /// Verifies NIP-01 id and signature before focused Food admission.
    166 pub fn verify_and_admit_food_availability_event(
    167     event: EventEnvelope,
    168 ) -> Result<RadrootsFoodAvailabilityAdmissionOutcome, RadrootsFoodAvailabilityAdmissionError> {
    169     admit_verified_food_availability_event(verify_nip01_event(event)?)
    170 }