traits.rs
1 use super::config::SourceRefreshOptions; 2 use crate::error::SourceError; 3 use crate::source::variable::ParsedVariable; 4 use compact_str::CompactString; 5 use std::sync::Arc; 6 7 #[derive(Debug, Clone, Hash, Eq, PartialEq)] 8 pub struct SourceId(CompactString); 9 10 impl SourceId { 11 pub fn new(id: impl Into<CompactString>) -> Self { 12 Self(id.into()) 13 } 14 15 pub fn as_str(&self) -> &str { 16 &self.0 17 } 18 } 19 20 impl From<&str> for SourceId { 21 fn from(s: &str) -> Self { 22 Self(CompactString::new(s)) 23 } 24 } 25 26 impl From<String> for SourceId { 27 fn from(s: String) -> Self { 28 Self(CompactString::new(s)) 29 } 30 } 31 32 impl std::fmt::Display for SourceId { 33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 34 write!(f, "{}", self.0) 35 } 36 } 37 38 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 39 pub struct Priority(pub u32); 40 41 impl Priority { 42 pub const SHELL: Priority = Priority(100); 43 pub const FILE: Priority = Priority(50); 44 pub const MEMORY: Priority = Priority(30); 45 pub const REMOTE: Priority = Priority(75); 46 } 47 48 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 49 pub enum SourceType { 50 File, 51 Shell, 52 Memory, 53 Remote, 54 } 55 56 bitflags::bitflags! { 57 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 58 pub struct SourceCapabilities: u32 { 59 const READ = 0b00000001; 60 const WRITE = 0b00000010; 61 const WATCH = 0b00000100; 62 const SECRETS = 0b00001000; 63 const VERSIONED = 0b00010000; 64 const CACHEABLE = 0b00100000; 65 const ASYNC_ONLY = 0b01000000; 66 } 67 } 68 69 impl Default for SourceCapabilities { 70 fn default() -> Self { 71 Self::READ | Self::CACHEABLE 72 } 73 } 74 75 #[derive(Debug, Clone)] 76 pub struct SourceSnapshot { 77 pub source_id: SourceId, 78 pub variables: Arc<[ParsedVariable]>, 79 pub timestamp: std::time::Instant, 80 pub version: Option<u64>, 81 } 82 83 #[derive(Debug, Clone, Default)] 84 pub struct SourceMetadata { 85 pub display_name: Option<CompactString>, 86 pub description: Option<CompactString>, 87 pub last_refreshed: Option<std::time::Instant>, 88 pub error_count: u32, 89 } 90 91 pub trait EnvSource: Send + Sync { 92 fn id(&self) -> &SourceId; 93 fn source_type(&self) -> SourceType; 94 fn priority(&self) -> Priority; 95 fn capabilities(&self) -> SourceCapabilities; 96 fn load(&self) -> Result<SourceSnapshot, SourceError>; 97 98 /// Returns true if the source data may have changed since the last load. 99 /// 100 /// Implementations should track internal version/state changes and compare 101 /// against the last loaded state. This allows callers to skip reloading 102 /// sources that haven't changed. 103 fn has_changed(&self) -> bool; 104 105 fn invalidate(&self); 106 fn metadata(&self) -> SourceMetadata { 107 SourceMetadata::default() 108 } 109 110 fn refresh(&self, _options: &SourceRefreshOptions) { 111 self.invalidate(); 112 } 113 } 114 115 #[cfg(feature = "async")] 116 #[async_trait::async_trait] 117 pub trait AsyncEnvSource: Send + Sync { 118 fn id(&self) -> &SourceId; 119 fn source_type(&self) -> SourceType; 120 fn priority(&self) -> Priority; 121 fn capabilities(&self) -> SourceCapabilities; 122 123 async fn load(&self) -> Result<SourceSnapshot, SourceError>; 124 async fn refresh(&self) -> Result<bool, SourceError>; 125 126 fn metadata(&self) -> SourceMetadata { 127 SourceMetadata::default() 128 } 129 }