praborrow_core/
lib.rs

1//! Core primitives for distributed ownership enforcement.
2//!
3//! This crate provides `Sovereign<T>`, a wrapper type that tracks ownership
4//! across network boundaries. When a resource is "annexed" (moved to another node),
5//! local access is prohibited.
6//!
7//! # The Garuda Proof System
8//!
9//! With `praborrow-prover`, this crate now supports **formally verified** state
10//! transitions. Use `annex_verified()` to require SMT proof before annexation.
11//!
12//! # Safety
13//! Uses `UnsafeCell` and `AtomicU8` for interior mutability with thread-safety.
14//! The `Send`/`Sync` implementations are safe when `T` is `Send`/`Sync`.
15
16#![cfg_attr(not(feature = "std"), no_std)]
17
18extern crate alloc;
19
20use alloc::collections::BTreeMap;
21use alloc::string::String;
22use core::cell::UnsafeCell;
23use core::marker::PhantomData;
24use core::ops::{Deref, DerefMut};
25use core::sync::atomic::{AtomicU8, Ordering};
26
27/// The state of a Sovereign resource.
28/// 0: Domestic (Local jurisdiction)
29/// 1: Exiled (Foreign jurisdiction - moved to another node)
30#[derive(Debug, PartialEq, Eq, Clone, Copy)]
31#[repr(u8)]
32pub enum SovereignState {
33    Domestic = 0,
34    Exiled = 1,
35}
36
37impl core::fmt::Display for SovereignState {
38    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
39        match self {
40            SovereignState::Domestic => f.write_str("Domestic"),
41            SovereignState::Exiled => f.write_str("Exiled"),
42        }
43    }
44}
45
46/// A token that proves a resource has been returned to domestic jurisdiction.
47///
48/// This token is required to call `Sovereign::repatriate`. It can only be constructed
49/// by trusted system components (like the lease manager) that can guarantee the
50/// resource is safe to reclaim.
51pub struct RepatriationToken {
52    _private: (),
53}
54
55impl RepatriationToken {
56    /// Creates a new repatriation token.
57    ///
58    /// # Safety
59    ///
60    /// This function is unsafe because creating a token allows the holder to
61    /// repatriate a sovereign resource. The caller must guarantee that the
62    /// resource is indeed back in domestic jurisdiction and no longer accessed
63    /// remotely.
64    pub unsafe fn new() -> Self {
65        Self { _private: () }
66    }
67}
68
69/// A wrapper that enforces ownership semantics across network boundaries.
70///
71/// "Memory safety with sovereign integrity."
72pub struct Sovereign<T> {
73    inner: UnsafeCell<T>,
74    state: AtomicU8,
75}
76
77/// Error enforcing constitutional invariants.
78#[non_exhaustive]
79#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
80pub enum ConstitutionError {
81    #[error("Invariant violated: {expression}. Values: {values:?}")]
82    InvariantViolation {
83        expression: String,
84        values: BTreeMap<String, String>,
85    },
86}
87
88/// Error returned when accessing a Sovereign resource fails.
89#[non_exhaustive]
90#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
91pub enum SovereigntyError {
92    /// Resource is under foreign jurisdiction (Exiled).
93    #[error("SOVEREIGNTY VIOLATION: Resource is under foreign jurisdiction.")]
94    ForeignJurisdiction,
95}
96
97impl<T> Sovereign<T> {
98    /// Creates a new Sovereign resource under domestic jurisdiction.
99    ///
100    /// # Atomic Ordering
101    ///
102    /// Uses `SeqCst` ordering for maximum safety in distributed scenarios.
103    /// This ensures all threads see state changes in a consistent order,
104    /// which is critical for ownership semantics across network boundaries.
105    #[must_use = "Sovereign resources must be managed carefully"]
106    pub fn new(value: T) -> Self {
107        Self {
108            inner: UnsafeCell::new(value),
109            state: AtomicU8::new(SovereignState::Domestic as u8),
110        }
111    }
112
113    /// Creates a new Sovereign resource that is already under foreign jurisdiction.
114    ///
115    /// This is useful for nodes receiving data that has been transferred from
116    /// another node - the resource starts in an Exiled state.
117    ///
118    /// # Example
119    ///
120    /// ```
121    /// use praborrow_core::{Sovereign, SovereignState};
122    ///
123    /// let foreign_data = Sovereign::new_exiled(42i32);
124    /// assert!(foreign_data.is_exiled());
125    /// ```
126    #[must_use = "Sovereign resources must be managed carefully"]
127    pub fn new_exiled(value: T) -> Self {
128        Self {
129            inner: UnsafeCell::new(value),
130            state: AtomicU8::new(SovereignState::Exiled as u8),
131        }
132    }
133
134    /// Annexes the resource, moving it to foreign jurisdiction.
135    ///
136    /// Once annexed, the resource cannot be accessed locally.
137    /// Access attempts will result in a Sovereignty Violation.
138    #[must_use = "Annexation result should be checked"]
139    pub fn annex(&self) -> Result<(), AnnexError> {
140        let current = self.state.load(Ordering::SeqCst);
141        if current == SovereignState::Exiled as u8 {
142            return Err(AnnexError::AlreadyExiled);
143        }
144
145        // Diplomatically transition state
146        self.state
147            .store(SovereignState::Exiled as u8, Ordering::SeqCst);
148
149        tracing::debug!(
150            from = "Domestic",
151            to = "Exiled",
152            "Resource annexed to foreign jurisdiction"
153        );
154
155        Ok(())
156    }
157
158    /// Returns a reference to the inner value without jurisdiction check.
159    ///
160    /// # Safety
161    ///
162    /// This is safe because we're returning a shared reference and the caller
163    /// is responsible for ensuring the resource is domestic. Use `try_get()`
164    /// for safe access with jurisdiction verification.
165    pub fn inner_ref(&self) -> &T {
166        // SAFETY: We're only reading, and this is safe when called from
167        // contexts that have already verified jurisdiction.
168        unsafe { &*self.inner.get() }
169    }
170
171    /// Returns the current state of the resource.
172    #[inline]
173    pub fn state(&self) -> SovereignState {
174        match self.state.load(Ordering::SeqCst) {
175            0 => SovereignState::Domestic,
176            _ => SovereignState::Exiled,
177        }
178    }
179
180    /// Returns `true` if the resource is under domestic jurisdiction.
181    #[inline]
182    pub fn is_domestic(&self) -> bool {
183        self.state.load(Ordering::SeqCst) == SovereignState::Domestic as u8
184    }
185
186    /// Returns `true` if the resource is under foreign jurisdiction (exiled).
187    #[inline]
188    pub fn is_exiled(&self) -> bool {
189        self.state.load(Ordering::SeqCst) == SovereignState::Exiled as u8
190    }
191
192    /// Attempts to get a reference to the value, returning an error if Exiled.
193    #[must_use = "Check jurisdiction result"]
194    pub fn try_get(&self) -> Result<&T, SovereigntyError> {
195        if self.is_exiled() {
196            return Err(SovereigntyError::ForeignJurisdiction);
197        }
198        // SAFETY: We verified the resource is domestic.
199        unsafe { Ok(&*self.inner.get()) }
200    }
201
202    /// Attempts to get a mutable reference to the value, returning an error if Exiled.
203    #[must_use = "Check jurisdiction result"]
204    pub fn try_get_mut(&mut self) -> Result<&mut T, SovereigntyError> {
205        if self.is_exiled() {
206            return Err(SovereigntyError::ForeignJurisdiction);
207        }
208        // SAFETY: We verified resource is domestic and have &mut self.
209        unsafe { Ok(&mut *self.inner.get()) }
210    }
211
212    /// Repatriates a resource, transitioning it from Exiled back to Domestic.
213    ///
214    /// Requires a `RepatriationToken` as proof that the resource is safe to reclaim.
215    ///
216    /// # Example
217    ///
218    /// ```
219    /// use praborrow_core::{Sovereign, SovereignState, RepatriationToken};
220    ///
221    /// let resource = Sovereign::new(42i32);
222    /// resource.annex().unwrap();
223    /// assert!(resource.is_exiled());
224    ///
225    /// // ... resource is sent to foreign node and returned ...
226    ///
227    /// // SAFETY: construction of token implies safety verification
228    /// let token = unsafe { RepatriationToken::new() };
229    /// resource.repatriate(token);
230    /// assert!(resource.is_domestic());
231    /// ```
232    #[must_use = "Ensure resource is actually repatriated"]
233    pub fn repatriate(&self, _token: RepatriationToken) {
234        let previous = self
235            .state
236            .swap(SovereignState::Domestic as u8, Ordering::SeqCst);
237
238        if previous == SovereignState::Exiled as u8 {
239            tracing::debug!(
240                from = "Exiled",
241                to = "Domestic",
242                "Resource repatriated to domestic jurisdiction"
243            );
244        }
245    }
246
247    /// Checks if the resource is currently domestic, panicking if not.
248    ///
249    /// Used internally by Deref/DerefMut. Prefer `try_get()` for non-panicking access.
250    fn verify_jurisdiction(&self) {
251        if self.is_exiled() {
252            panic!("SOVEREIGNTY VIOLATION: Resource is under foreign jurisdiction.");
253        }
254    }
255
256    /// Maps a function over the domestic sovereign value.
257    ///
258    /// If the resource is Exiled, returns `Err(SovereigntyError::ForeignJurisdiction)`
259    /// without evaluating the function.
260    ///
261    /// # Example
262    ///
263    /// ```
264    /// use praborrow_core::Sovereign;
265    /// let s = Sovereign::new(5);
266    /// let result = s.map(|x| x * 2).unwrap();
267    /// assert_eq!(result, 10);
268    /// ```
269    pub fn map<F, U>(&self, f: F) -> Result<U, SovereigntyError>
270    where
271        F: FnOnce(&T) -> U,
272    {
273        if self.is_exiled() {
274            return Err(SovereigntyError::ForeignJurisdiction);
275        }
276        // SAFETY: We verified resource is domestic.
277        Ok(f(unsafe { &*self.inner.get() }))
278    }
279
280    /// Chains a function that returns a Result over the domestic sovereign value.
281    ///
282    /// This is useful for sequencing operations that might fail or themselves require
283    /// jurisdiction checks.
284    pub fn and_then<F, U>(&self, f: F) -> Result<U, SovereigntyError>
285    where
286        F: FnOnce(&T) -> Result<U, SovereigntyError>,
287    {
288        if self.is_exiled() {
289            return Err(SovereigntyError::ForeignJurisdiction);
290        }
291        // SAFETY: We verified resource is domestic.
292        f(unsafe { &*self.inner.get() })
293    }
294
295    /// Returns a reference to the inner value if it matches the predicate.
296    ///
297    /// # Returns
298    ///
299    /// - `Ok(Some(&T))` if domestic and predicate is true
300    /// - `Ok(None)` if domestic and predicate is false
301    /// - `Err(ForeignJurisdiction)` if exiled
302    pub fn filter<P>(&self, predicate: P) -> Result<Option<&T>, SovereigntyError>
303    where
304        P: FnOnce(&T) -> bool,
305    {
306        if self.is_exiled() {
307            return Err(SovereigntyError::ForeignJurisdiction);
308        }
309        // SAFETY: We verified resource is domestic.
310        let val = unsafe { &*self.inner.get() };
311        if predicate(val) {
312            Ok(Some(val))
313        } else {
314            Ok(None)
315        }
316    }
317
318    /// Modifies the value in-place if domestic.
319    ///
320    /// # Example
321    ///
322    /// ```
323    /// use praborrow_core::Sovereign;
324    /// let mut s = Sovereign::new(5);
325    /// s.modify(|x| *x += 1).unwrap();
326    /// assert_eq!(*s, 6);
327    /// ```
328    pub fn modify<F>(&mut self, f: F) -> Result<(), SovereigntyError>
329    where
330        F: FnOnce(&mut T),
331    {
332        if self.is_exiled() {
333            return Err(SovereigntyError::ForeignJurisdiction);
334        }
335        // SAFETY: We verified resource is domestic and have &mut self.
336        f(unsafe { &mut *self.inner.get() });
337        Ok(())
338    }
339}
340
341impl<T: core::fmt::Debug> core::fmt::Debug for Sovereign<T> {
342    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
343        let state = self.state();
344        match state {
345            SovereignState::Domestic => {
346                // SAFETY: We checked state is Domestic.
347                let val = unsafe { &*self.inner.get() };
348                f.debug_struct("Sovereign")
349                    .field("state", &state)
350                    .field("inner", val)
351                    .finish()
352            }
353            SovereignState::Exiled => {
354                f.debug_struct("Sovereign")
355                    .field("state", &state)
356                    .field("inner", &"<Inaccessible>")
357                    .finish()
358            }
359        }
360    }
361}
362
363impl<T> Deref for Sovereign<T> {
364    type Target = T;
365
366    fn deref(&self) -> &Self::Target {
367        self.verify_jurisdiction();
368        // SAFETY: We've verified the resource is domestic, so access is valid.
369        unsafe { &*self.inner.get() }
370    }
371}
372
373impl<T> DerefMut for Sovereign<T> {
374    fn deref_mut(&mut self) -> &mut Self::Target {
375        self.verify_jurisdiction();
376        // SAFETY: We've verified the resource is domestic and have &mut self.
377        unsafe { &mut *self.inner.get() }
378    }
379}
380
381// SAFETY: Sovereign<T> is Send/Sync if T is Send/Sync, as we use AtomicU8 for state
382// and check it before access. The UnsafeCell is protected by the atomic state check.
383unsafe impl<T: Send> Send for Sovereign<T> {}
384unsafe impl<T: Sync> Sync for Sovereign<T> {}
385
386/// Protocol for enforcing constitutional invariants (runtime checks).
387///
388/// Types implementing this trait can validate their internal state against
389/// a set of invariants defined via the `#[derive(Constitution)]` macro.
390pub trait CheckProtocol {
391    /// Enforces all invariants, returning an error if any are violated.
392    ///
393    /// # Returns
394    ///
395    /// - `Ok(())` if all invariants are satisfied
396    /// - `Err(ConstitutionError)` containing a description of the violated invariant
397    ///
398    /// # Example
399    ///
400    /// ```ignore
401    /// use praborrow_core::CheckProtocol;
402    ///
403    /// let data = MyStruct { value: -1 };
404    /// match data.enforce_law() {
405    ///     Ok(()) => println!("All invariants satisfied"),
406    ///     Err(e) => println!("Invariant violated: {}", e),
407    /// }
408    /// ```
409    fn enforce_law(&self) -> Result<(), ConstitutionError>;
410}
411
412/// A value carrying cryptographic proof of verification.
413///
414/// This type can only be constructed by successful SMT verification.
415/// Its existence in a type signature proves that formal verification occurred.
416///
417/// # Type Safety Guarantee
418///
419/// `ProofCarrying<T>` cannot be forged - the private `_proof` field
420/// ensures only the prover crate can construct it.
421#[derive(Debug)]
422pub struct ProofCarrying<T> {
423    /// The carried value.
424    pub value: T,
425    /// Private marker ensuring construction only via verification.
426    _proof: PhantomData<()>,
427}
428
429impl<T> ProofCarrying<T> {
430    /// Creates a new proof-carrying value.
431    ///
432    /// This should only be called after successful verification.
433    #[doc(hidden)]
434    pub fn new_unchecked(value: T) -> Self {
435        Self {
436            value,
437            _proof: PhantomData,
438        }
439    }
440
441    /// Extracts the inner value, consuming the proof.
442    pub fn into_inner(self) -> T {
443        self.value
444    }
445}
446
447impl<T: Clone> Clone for ProofCarrying<T> {
448    fn clone(&self) -> Self {
449        Self {
450            value: self.value.clone(),
451            _proof: PhantomData,
452        }
453    }
454}
455
456/// Error type for verified annexation operations.
457#[non_exhaustive]
458#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
459pub enum AnnexError {
460    /// Resource is already under foreign jurisdiction.
461    #[error("Resource is already under foreign jurisdiction")]
462    AlreadyExiled,
463    /// SMT verification failed.
464    #[error("Verification failed: {0}")]
465    VerificationFailed(String),
466    /// Prover encountered an error.
467    #[error("Prover error: {0}")]
468    ProverError(String),
469}
470
471/// Error returned when a lease operation fails.
472#[non_exhaustive]
473#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
474pub enum LeaseError {
475    /// Resource is already leased to another holder.
476    #[error("Resource is already leased to another holder")]
477    AlreadyLeased,
478    /// Resource is under foreign jurisdiction.
479    #[error("Resource is under foreign jurisdiction")]
480    ForeignJurisdiction,
481    /// Lease duration must be non-zero.
482    #[error("Lease duration must be non-zero")]
483    InvalidDuration,
484}
485
486/// Represents a lease on a Sovereign resource.
487pub struct Lease<T> {
488    /// The holder's unique identifier.
489    pub holder: u128,
490    /// Duration of the lease.
491    pub duration: core::time::Duration,
492    /// Phantom data for the resource type.
493    _phantom: PhantomData<T>,
494}
495
496impl<T> Lease<T> {
497    /// Creates a new lease.
498    ///
499    /// # Duration Validation
500    ///
501    /// If `duration` is zero, returns `Err(LeaseError::InvalidDuration)`.
502    pub fn new(holder: u128, duration: core::time::Duration) -> Result<Self, LeaseError> {
503        if duration.is_zero() {
504            return Err(LeaseError::InvalidDuration);
505        }
506
507        Ok(Self {
508            holder,
509            duration,
510            _phantom: PhantomData,
511        })
512    }
513
514    /// Returns the duration of the lease.
515    #[inline]
516    pub fn duration(&self) -> core::time::Duration {
517        self.duration
518    }
519
520    /// Returns the holder ID.
521    #[inline]
522    pub fn holder(&self) -> u128 {
523        self.holder
524    }
525}
526
527/// Trait for distributed borrow operations.
528pub trait DistributedBorrow<T> {
529    /// Attempt to acquire a lease on the resource.
530    fn try_hire(
531        &self,
532        candidate_id: u128,
533        term: core::time::Duration,
534    ) -> Result<Lease<T>, LeaseError>;
535}
536
537impl<T> DistributedBorrow<T> for Sovereign<T> {
538    fn try_hire(
539        &self,
540        candidate_id: u128,
541        term: core::time::Duration,
542    ) -> Result<Lease<T>, LeaseError> {
543        let current = self.state.load(Ordering::SeqCst);
544        if current == SovereignState::Exiled as u8 {
545            return Err(LeaseError::AlreadyLeased);
546        }
547
548        // Transition to exiled state (leased)
549        self.state
550            .store(SovereignState::Exiled as u8, Ordering::SeqCst);
551        Lease::<T>::new(candidate_id, term)
552    }
553}
554
555/// Extension trait for Sovereign types whose inner types implement formal verification.
556///
557/// This trait is automatically implemented for `Sovereign<T>` where `T` can be
558/// formally verified via the Garuda Proof System.
559pub trait VerifiedAnnex<T> {
560    /// Annexes the resource after successful formal verification.
561    ///
562    /// Unlike `annex()`, this method requires mathematical proof that all
563    /// invariants are satisfied before the state transition occurs.
564    ///
565    /// # Returns
566    ///
567    /// - `Ok(ProofCarrying<()>)` - Verification passed, resource is now Exiled
568    /// - `Err(AnnexError)` - Verification failed or resource already Exiled
569    ///
570    /// # Example
571    ///
572    /// ```ignore
573    /// use praborrow_core::{Sovereign, VerifiedAnnex};
574    ///
575    /// let resource = Sovereign::new(MyVerifiableStruct { balance: 100 });
576    ///
577    /// // This will run SMT verification before annexing
578    /// match resource.annex_verified() {
579    ///     Ok(proof) => println!("Annexation proven safe!"),
580    ///     Err(e) => println!("Cannot annex: {}", e),
581    /// }
582    /// ```
583    fn annex_verified(&self) -> Result<ProofCarrying<()>, AnnexError>;
584}
585
586// Note: The actual implementation of VerifiedAnnex requires praborrow-prover,
587// which would create a circular dependency. Instead, the implementation is
588// provided via blanket impl in praborrow-prover or via the facade crate.
589//
590// Users should use the `praborrow` facade crate for full functionality.
591
592#[cfg(test)]
593mod tests {
594    use super::*;
595
596    #[test]
597    fn test_sovereign_new() {
598        let s = Sovereign::new(42i32);
599        assert_eq!(s.state(), SovereignState::Domestic);
600        assert!(s.is_domestic());
601        assert!(!s.is_exiled());
602    }
603
604    #[test]
605    fn test_sovereign_new_exiled() {
606        let s = Sovereign::new_exiled(42i32);
607        assert_eq!(s.state(), SovereignState::Exiled);
608        assert!(s.is_exiled());
609        assert!(!s.is_domestic());
610    }
611
612    #[test]
613    fn test_sovereign_deref() {
614        let s = Sovereign::new(42i32);
615        assert_eq!(*s, 42);
616    }
617
618    #[test]
619    fn test_sovereign_deref_mut() {
620        let mut s = Sovereign::new(42i32);
621        *s = 100;
622        assert_eq!(*s, 100);
623    }
624
625    #[test]
626    fn test_sovereign_annex() {
627        let s = Sovereign::new(42i32);
628        assert!(s.annex().is_ok());
629        assert_eq!(s.state(), SovereignState::Exiled);
630        assert!(s.is_exiled());
631    }
632
633    #[test]
634    fn test_sovereign_double_annex() {
635        let s = Sovereign::new(42i32);
636        assert!(s.annex().is_ok());
637        assert!(s.annex().is_err());
638    }
639
640    #[test]
641    fn test_sovereign_repatriate() {
642        let s = Sovereign::new(42i32);
643        s.annex().unwrap();
644        assert!(s.is_exiled());
645
646        // SAFETY: In test context, we control both sides
647        // SAFETY: In test context, we control both sides
648        let token = unsafe { RepatriationToken::new() };
649        let _ = s.repatriate(token);
650        assert!(s.is_domestic());
651
652        // Should be able to access again
653        assert_eq!(*s, 42);
654    }
655
656    #[test]
657    #[should_panic(expected = "SOVEREIGNTY VIOLATION")]
658    fn test_sovereignty_violation() {
659        let s = Sovereign::new(42i32);
660        s.annex().unwrap();
661        let _ = *s; // This should panic
662    }
663
664    #[test]
665    fn test_try_get_domestic() {
666        let s = Sovereign::new(42i32);
667        assert_eq!(*s.try_get().unwrap(), 42);
668    }
669
670    #[test]
671    fn test_try_get_exiled() {
672        let s = Sovereign::new(42i32);
673        s.annex().unwrap();
674        assert!(matches!(
675            s.try_get(),
676            Err(SovereigntyError::ForeignJurisdiction)
677        ));
678    }
679
680    #[test]
681    fn test_proof_carrying() {
682        let proof = ProofCarrying::new_unchecked(42i32);
683        assert_eq!(proof.value, 42);
684        assert_eq!(proof.into_inner(), 42);
685    }
686
687    #[test]
688    fn test_annex_error_display() {
689        let e = AnnexError::AlreadyExiled;
690        assert!(e.to_string().contains("foreign jurisdiction"));
691
692        let e = AnnexError::VerificationFailed("test".to_string());
693        assert!(e.to_string().contains("test"));
694    }
695
696    #[test]
697    fn test_lease_zero_duration_fails() {
698        let lease = Lease::<i32>::new(1, core::time::Duration::ZERO);
699        assert!(matches!(lease, Err(LeaseError::InvalidDuration)));
700    }
701
702    #[test]
703    fn test_lease_normal_duration() {
704        let duration = core::time::Duration::from_secs(10);
705        let lease = Lease::<i32>::new(1, duration).unwrap();
706        assert_eq!(lease.duration(), duration);
707        assert_eq!(lease.holder(), 1);
708    }
709
710    #[test]
711    fn test_map_domestic() {
712        let s = Sovereign::new(10);
713        let res = s.map(|x| x * 2);
714        assert_eq!(res, Ok(20));
715    }
716
717    #[test]
718    fn test_map_exiled() {
719        let s = Sovereign::new(10);
720        s.annex().unwrap();
721        let res = s.map(|x| x * 2);
722        assert_eq!(res, Err(SovereigntyError::ForeignJurisdiction));
723    }
724
725    #[test]
726    fn test_and_then() {
727        let s = Sovereign::new(10);
728        let res = s.and_then(|x| {
729            if *x > 5 {
730                Ok(*x * 2)
731            } else {
732                Err(SovereigntyError::ForeignJurisdiction) // Just using this error for test
733            }
734        });
735        assert_eq!(res, Ok(20));
736    }
737
738    #[test]
739    fn test_filter() {
740        let s = Sovereign::new(10);
741
742        // Match
743        let res1 = s.filter(|x| *x > 5);
744        assert_eq!(res1, Ok(Some(&10)));
745
746        // No match
747        let res2 = s.filter(|x| *x < 5);
748        assert_eq!(res2, Ok(None));
749
750        // Exiled
751        s.annex().unwrap();
752        let res3 = s.filter(|x| *x > 5);
753        assert_eq!(res3, Err(SovereigntyError::ForeignJurisdiction));
754    }
755
756    #[test]
757    fn test_modify() {
758        let mut s = Sovereign::new(10);
759        s.modify(|x| *x += 1).unwrap();
760        assert_eq!(*s, 11);
761
762        s.annex().unwrap();
763        let res = s.modify(|x| *x += 1);
764        assert_eq!(res, Err(SovereigntyError::ForeignJurisdiction));
765    }
766}