shared-struct 0.1.2

Proc-macro for turning a struct into a shared concurrent wrapper
Documentation

shared-struct

A procedural macro that transforms a struct into a shared, cheaply-cloneable wrapper with per-field fine-grained locking. Each field gets its own tokio::sync::Mutex, so concurrent access to different fields does not block. The wrapper itself is an Arc — cloning is cheap and all clones share the same data.

Usage

use shared_struct::shared;

#[shared]
pub struct Context {
    pub name: String,
    count: u32,
    #[raw]
    pub tag: String,
}

What gets generated

#[derive(Clone)]
pub struct Context(::std::sync::Arc<ContextInner>);

pub struct ContextInner {
    pub name: ::tokio::sync::Mutex<String>,
    count: ::tokio::sync::Mutex<u32>,
    pub tag: String,
}

impl Context {
    pub fn new(name: String, count: u32, tag: String) -> Self {
        Self(::std::sync::Arc::new(ContextInner {
            name: ::tokio::sync::Mutex::new(name),
            count: ::tokio::sync::Mutex::new(count),
            tag,
        }))
    }
    pub async fn name(&self) -> ::tokio::sync::MutexGuard<'_, String> {
        self.0.name.lock().await
    }
    async fn count(&self) -> ::tokio::sync::MutexGuard<'_, u32> {
        self.0.count.lock().await
    }
    pub fn tag(&self) -> &String {
        &self.0.tag
    }
}

Field attributes

Attribute Storage Accessor
(default) Mutex<T> async fn field(&self) -> MutexGuard<T>
#[raw] T (no lock) fn field(&self) -> &T

Clone semantics

clone() is Arc::clone — all clones share the same data.

let ctx = Context::new("hello".to_string(), 0, "t".to_string());
let ctx2 = ctx.clone();

*ctx.name().await = "world".to_string();
assert_eq!(*ctx2.name().await, "world"); // same Arc

Visibility

Field visibility is preserved on ContextInner and all accessors.

#[shared]
pub struct Foo {
    pub public_field: String,
    pub(crate) crate_field: u32,
    private_field: bool,
}

Dependencies

Runtime crate requires tokio with the sync feature.