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