Skip to main content

Subscription

Struct Subscription 

Source
pub struct Subscription<T: Clone + Send + Sync + 'static> { /* private fields */ }
Expand description

A RAII guard for an observer subscription that automatically unsubscribes when dropped

This struct provides automatic cleanup for observer subscriptions using RAII (Resource Acquisition Is Initialization) pattern. When a Subscription goes out of scope, its Drop implementation automatically removes the associated observer from the property.

This eliminates the need for manual unsubscribe() calls and helps prevent resource leaks in scenarios where observers might otherwise be forgotten.

§Type Requirements

The generic type T must implement the same traits as ObservableProperty<T>:

  • Clone: Required for observer notifications
  • Send: Required for transferring between threads
  • Sync: Required for concurrent access from multiple threads
  • 'static: Required for observer callbacks that may outlive the original scope

§Examples

§Basic RAII Subscription

use observable_property::ObservableProperty;
use std::sync::Arc;

let property = ObservableProperty::new(0);

{
    // Create subscription - observer is automatically registered
    let _subscription = property.subscribe_with_subscription(Arc::new(|old, new| {
        println!("Value changed: {} -> {}", old, new);
    }))?;

    property.set(42)?; // Observer is called: "Value changed: 0 -> 42"

    // When _subscription goes out of scope here, observer is automatically removed
}

property.set(100)?; // No observer output - subscription was automatically cleaned up

§Cross-Thread Subscription Management

use observable_property::ObservableProperty;
use std::sync::Arc;
use std::thread;

let property = Arc::new(ObservableProperty::new(0));
let property_clone = property.clone();

// Create subscription in main thread
let subscription = property.subscribe_with_subscription(Arc::new(|old, new| {
    println!("Observed: {} -> {}", old, new);
}))?;

// Move subscription to another thread for cleanup
let handle = thread::spawn(move || {
    // Subscription is still active here
    let _ = property_clone.set(42); // Will trigger observer
     
    // When subscription is dropped here (end of thread), observer is cleaned up
    drop(subscription);
});

handle.join().unwrap();
 
// Observer is no longer active
property.set(100)?; // No output

§Conditional Scoped Subscriptions

use observable_property::ObservableProperty;
use std::sync::Arc;

let counter = ObservableProperty::new(0);
let debug_mode = true;

if debug_mode {
    let _debug_subscription = counter.subscribe_with_subscription(Arc::new(|old, new| {
        println!("Debug: counter {} -> {}", old, new);
    }))?;
     
    counter.set(1)?; // Prints debug info
    counter.set(2)?; // Prints debug info
     
    // Debug subscription automatically cleaned up when exiting if block
}

counter.set(3)?; // No debug output (subscription was cleaned up)

§Thread Safety

Like ObservableProperty itself, Subscription is thread-safe. It can be safely sent between threads and the automatic cleanup will work correctly even if the subscription is dropped from a different thread than where it was created.

Trait Implementations§

Source§

impl<T: Clone + Send + Sync + 'static> Debug for Subscription<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Debug implementation that shows the subscription ID without exposing internals

Source§

impl<T: Clone + Send + Sync + 'static> Drop for Subscription<T>

Source§

fn drop(&mut self)

Automatically removes the associated observer when the subscription is dropped

This implementation provides automatic cleanup by removing the observer from the property’s observer list when the Subscription goes out of scope.

§Error Handling

If the property’s lock is poisoned or inaccessible during cleanup, the error is silently ignored using the let _ = ... pattern. This is intentional because:

  1. Drop implementations should not panic
  2. If the property is poisoned, it’s likely unusable anyway
  3. There’s no meaningful way to handle cleanup errors in a destructor
§Thread Safety

This method is safe to call from any thread, even if the subscription was created on a different thread.

Auto Trait Implementations§

§

impl<T> Freeze for Subscription<T>

§

impl<T> RefUnwindSafe for Subscription<T>

§

impl<T> Send for Subscription<T>

§

impl<T> Sync for Subscription<T>

§

impl<T> Unpin for Subscription<T>

§

impl<T> UnsafeUnpin for Subscription<T>

§

impl<T> UnwindSafe for Subscription<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.