Skip to main content

lib_q_core/contexts/
base.rs

1//! Base context implementation for lib-Q Core
2//!
3//! This module provides the foundational context structure that all
4//! cryptographic operation contexts inherit from.
5
6#[cfg(feature = "alloc")]
7use alloc::boxed::Box;
8use core::marker::PhantomData;
9
10use crate::api::CryptoProvider;
11use crate::error::Result;
12
13/// Base context trait that all cryptographic contexts must implement
14pub trait ContextOps {
15    /// Initialize the context
16    fn init(&mut self) -> Result<()>;
17
18    /// Check if the context is initialized
19    fn is_initialized(&self) -> bool;
20
21    /// Get the provider (if any)
22    fn provider(&self) -> Option<&dyn CryptoProvider>;
23
24    /// Set the provider
25    fn set_provider(&mut self, provider: Box<dyn CryptoProvider>);
26}
27
28/// Generic context wrapper that provides common functionality
29#[cfg(feature = "alloc")]
30pub struct BaseContext<T> {
31    _phantom: PhantomData<T>,
32    initialized: bool,
33    provider: Option<Box<dyn CryptoProvider>>,
34}
35
36#[cfg(feature = "alloc")]
37impl<T> BaseContext<T> {
38    /// Create a new uninitialized context
39    pub fn new() -> Self {
40        Self {
41            _phantom: PhantomData,
42            initialized: false,
43            provider: None,
44        }
45    }
46
47    /// Create a new context with a provider
48    pub fn with_provider(provider: Box<dyn CryptoProvider>) -> Self {
49        Self {
50            _phantom: PhantomData,
51            initialized: false,
52            provider: Some(provider),
53        }
54    }
55
56    /// Initialize the context
57    pub fn init(&mut self) -> Result<()> {
58        if self.initialized {
59            return Ok(());
60        }
61        self.initialized = true;
62        Ok(())
63    }
64
65    /// Check if the context is initialized
66    pub fn is_initialized(&self) -> bool {
67        self.initialized
68    }
69
70    /// Get the provider (if any)
71    pub fn provider(&self) -> Option<&dyn CryptoProvider> {
72        self.provider.as_deref()
73    }
74
75    /// Set the provider
76    pub fn set_provider(&mut self, provider: Box<dyn CryptoProvider>) {
77        self.provider = Some(provider);
78    }
79
80    /// Ensure the context is initialized
81    pub fn ensure_initialized(&mut self) -> Result<()> {
82        if !self.initialized {
83            self.init()?;
84        }
85        Ok(())
86    }
87}
88
89#[cfg(feature = "alloc")]
90impl<T> Default for BaseContext<T> {
91    fn default() -> Self {
92        Self::new()
93    }
94}
95
96/// Context builder for creating contexts with specific configurations
97#[cfg(feature = "alloc")]
98pub struct ContextBuilder<T> {
99    provider: Option<Box<dyn CryptoProvider>>,
100    _phantom: PhantomData<T>,
101}
102
103#[cfg(feature = "alloc")]
104impl<T> ContextBuilder<T> {
105    /// Create a new context builder
106    pub fn new() -> Self {
107        Self {
108            provider: None,
109            _phantom: PhantomData,
110        }
111    }
112
113    /// Set the provider for the context
114    pub fn with_provider(mut self, provider: Box<dyn CryptoProvider>) -> Self {
115        self.provider = Some(provider);
116        self
117    }
118
119    /// Build the context
120    pub fn build(self) -> BaseContext<T> {
121        match self.provider {
122            Some(provider) => BaseContext::with_provider(provider),
123            None => BaseContext::new(),
124        }
125    }
126}
127
128#[cfg(feature = "alloc")]
129impl<T> Default for ContextBuilder<T> {
130    fn default() -> Self {
131        Self::new()
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138    use crate::api::CryptoProvider;
139
140    // Mock provider for testing
141    struct MockProvider;
142
143    impl CryptoProvider for MockProvider {
144        fn kem(&self) -> Option<&dyn crate::api::KemOperations> {
145            None
146        }
147        fn signature(&self) -> Option<&dyn crate::api::SignatureOperations> {
148            None
149        }
150        fn hash(&self) -> Option<&dyn crate::api::HashOperations> {
151            None
152        }
153        fn aead(&self) -> Option<&dyn crate::api::AeadOperations> {
154            None
155        }
156    }
157
158    #[test]
159    fn test_base_context_creation() {
160        let context = BaseContext::<()>::new();
161        assert!(!context.is_initialized());
162        assert!(context.provider().is_none());
163    }
164
165    #[test]
166    fn test_base_context_with_provider() {
167        let provider = Box::new(MockProvider);
168        let context = BaseContext::<()>::with_provider(provider);
169        assert!(!context.is_initialized());
170        assert!(context.provider().is_some());
171    }
172
173    #[test]
174    fn test_base_context_initialization() {
175        let mut context = BaseContext::<()>::new();
176        assert!(!context.is_initialized());
177
178        let result = context.init();
179        assert!(result.is_ok());
180        assert!(context.is_initialized());
181
182        // Second initialization should be idempotent
183        let result = context.init();
184        assert!(result.is_ok());
185        assert!(context.is_initialized());
186    }
187
188    #[test]
189    fn test_base_context_provider_management() {
190        let mut context = BaseContext::<()>::new();
191        assert!(context.provider().is_none());
192
193        let provider = Box::new(MockProvider);
194        context.set_provider(provider);
195        assert!(context.provider().is_some());
196    }
197
198    #[test]
199    fn test_context_builder() {
200        let provider = Box::new(MockProvider);
201        let context = ContextBuilder::<()>::new().with_provider(provider).build();
202
203        assert!(!context.is_initialized());
204        assert!(context.provider().is_some());
205    }
206
207    #[test]
208    fn test_context_builder_default() {
209        let context = ContextBuilder::<()>::default().build();
210        assert!(!context.is_initialized());
211        assert!(context.provider().is_none());
212    }
213
214    #[test]
215    fn test_ensure_initialized() {
216        let mut context = BaseContext::<()>::new();
217        assert!(!context.is_initialized());
218
219        let result = context.ensure_initialized();
220        assert!(result.is_ok());
221        assert!(context.is_initialized());
222
223        // Second call should still work
224        let result = context.ensure_initialized();
225        assert!(result.is_ok());
226        assert!(context.is_initialized());
227    }
228}