A pit full of rusty nails
at main 164 lines 3.8 kB view raw
1use std::{convert::Infallible, ops::Deref, sync::Arc}; 2 3use axum::extract::{FromRef, FromRequestParts}; 4use nailconfig::NailConfig; 5use nailgen::{GeneratedTemplate, MarkovGen, Template, WarningTemplate}; 6use nailrng::FastRng; 7use nailspicy::SpicyPayloads; 8use rand::seq::IndexedRandom; 9 10pub struct Templates { 11 pub warning: WarningTemplate, 12 pub generated: GeneratedTemplate, 13} 14 15#[derive(Clone)] 16pub struct NailPayloads { 17 spicy_payloads: Option<Arc<SpicyPayloads>>, 18} 19 20impl core::fmt::Debug for NailPayloads { 21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 22 f.debug_struct("NailPayloads").finish_non_exhaustive() 23 } 24} 25 26impl NailPayloads { 27 pub fn get(&self) -> Option<Arc<SpicyPayloads>> { 28 self.spicy_payloads.clone() 29 } 30} 31 32/// Smart pointer for all available Markov chains. 33#[derive(Clone)] 34pub struct NailInputs { 35 chains: Arc<[MarkovGen]>, 36 templates: Arc<Templates>, 37} 38 39impl NailInputs { 40 pub fn new(chains: Arc<[MarkovGen]>, templates: Arc<Templates>) -> Self { 41 Self { chains, templates } 42 } 43 44 /// Pulls a random markov chain from the available list. Returns a cloned 45 /// pointer to the selected chain. 46 #[inline] 47 pub fn get_random_input(&self, rng: &mut FastRng) -> MarkovGen { 48 assert!(!self.chains.is_empty()); 49 50 if self.chains.len() == 1 { 51 self.chains[0].clone() 52 } else { 53 self.chains.choose(rng).unwrap().clone() 54 } 55 } 56 57 #[inline] 58 pub fn get_warning_template(&self) -> Template { 59 Template::from(self.templates.warning.clone()) 60 } 61 62 #[inline] 63 pub fn get_generated_template(&self) -> Template { 64 Template::from(self.templates.generated.clone()) 65 } 66} 67 68impl std::fmt::Debug for NailInputs { 69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 70 f.debug_tuple("NailInputs").finish_non_exhaustive() 71 } 72} 73 74#[derive(Debug, Clone)] 75pub struct AppConfig(Arc<NailConfig>); 76 77impl AppConfig { 78 pub fn clone_inner(&self) -> Arc<NailConfig> { 79 self.0.clone() 80 } 81} 82 83impl From<Arc<NailConfig>> for AppConfig { 84 #[inline] 85 fn from(value: Arc<NailConfig>) -> Self { 86 Self(value) 87 } 88} 89 90impl Deref for AppConfig { 91 type Target = NailConfig; 92 93 fn deref(&self) -> &Self::Target { 94 self.0.as_ref() 95 } 96} 97 98#[derive(Debug, Clone)] 99pub struct ServerState { 100 pub config: AppConfig, 101 pub inputs: NailInputs, 102 pub spicy_payloads: NailPayloads, 103} 104 105impl ServerState { 106 pub fn new( 107 config: impl Into<AppConfig>, 108 chains: Arc<[MarkovGen]>, 109 templates: Arc<Templates>, 110 spicy_payloads: Option<Arc<SpicyPayloads>>, 111 ) -> Self { 112 let config = config.into(); 113 114 Self { 115 config, 116 inputs: NailInputs { chains, templates }, 117 spicy_payloads: NailPayloads { spicy_payloads }, 118 } 119 } 120} 121 122impl FromRef<ServerState> for AppConfig { 123 #[inline] 124 fn from_ref(input: &ServerState) -> Self { 125 input.config.clone() 126 } 127} 128 129impl FromRef<ServerState> for NailInputs { 130 #[inline] 131 fn from_ref(input: &ServerState) -> Self { 132 input.inputs.clone() 133 } 134} 135 136impl<S> FromRequestParts<S> for AppConfig 137where 138 AppConfig: FromRef<S>, 139 S: Send + Sync, 140{ 141 type Rejection = Infallible; 142 143 async fn from_request_parts( 144 _parts: &mut axum::http::request::Parts, 145 state: &S, 146 ) -> Result<Self, Self::Rejection> { 147 Ok(AppConfig::from_ref(state)) 148 } 149} 150 151impl<S> FromRequestParts<S> for NailInputs 152where 153 NailInputs: FromRef<S>, 154 S: Send + Sync, 155{ 156 type Rejection = Infallible; 157 158 async fn from_request_parts( 159 _parts: &mut axum::http::request::Parts, 160 state: &S, 161 ) -> Result<Self, Self::Rejection> { 162 Ok(NailInputs::from_ref(state)) 163 } 164}