/ src / source / traits.rs
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  }