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