Skip to content

Commit

Permalink
doc: Completed documenting fieldx_aux crate
Browse files Browse the repository at this point in the history
And changed two badly choosen module and type names.
  • Loading branch information
vrurg committed Dec 4, 2024
1 parent 09eb6dc commit 2879b2c
Show file tree
Hide file tree
Showing 33 changed files with 994 additions and 634 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
![License](https://img.shields.io/github/license/vrurg/fieldx)
![Crates.io Version](https://img.shields.io/crates/v/fieldx)

# fieldx v0.1.8-beta.1
# fieldx v0.1.8-beta.2

Procedural macro for constructing structs with lazily initialized fields, builder pattern, and [`serde`] support
with a focus on declarative syntax.
Expand Down Expand Up @@ -251,7 +251,7 @@ assert_eq!( obj.description(), &String::from("count is ignored") );
```

Since the only `fieldx`-related failure that may happen when building a new object instance is a required field not
given a value, the `build()` method would return [`FieldXError`](errors::FieldXError) if this happens.
given a value, the `build()` method would return [`FieldXError`](error::FieldXError) if this happens.

## Crate Features

Expand Down Expand Up @@ -877,17 +877,17 @@ As it was mentioned in the [Basics](#basics) section, `fieldx` rewrites structur
following table reveals the final types of fields. `T` in the table represents the original field type, as specified
by the user; `O` is the original struct type.

| Field Parameters | Plain Type | Sync Type |
|------------------|---------------|-----------|
| `lazy` | `OnceCell<T>` | [`FXProxy<O, T>`] |
| `optional` (also activated with `clearer` and `proxy`) | `Option<T>` | [`FXRwLock<Option<T>>`] |
| `lock`, `reader` and/or `writer` | N/A | [`FXRwLock<T>`] |
| Field Parameters | Plain Type | Sync Type | Async Type |
|------------------|---------------|-----------|-----------|
| `lazy` | `OnceCell<T>` | [`FXProxySync<O, T>`] | [`FXProxyAsync<O,T>`] |
| `optional` (also activated with `clearer` and `proxy`) | `Option<T>` | [`FXRwLockSync<Option<T>>`][`sync::FXRwLockSync`] | [`FXRwLockAsync<Option<T>>`][`async::FXRwLockAsync`] |
| `lock`, `reader` and/or `writer` | N/A | [`FXRwLockSync<T>`][`sync::FXRwLockSync`] | [`FXRwLockAsync<T>`][`async::FXRwLockAsync`] |

Apparently, skipped fields retain their original type. Sure enough, if such a field is of non-`Send` or non-`Sync`
type the entire struct would be missing these traits despite all the efforts from the `fxstruct` macro.

There is also a difference in how the initialization of `lazy` fields is implemented. For plain fields this is done
directly in their accessor methods. Sync structs delegate this functionality to the [`FXProxy`] type.
directly in their accessor methods. Sync structs delegate this functionality to the [`FXProxySync`] type.

### Traits

Expand Down
4 changes: 4 additions & 0 deletions fieldx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
authors.workspace = true
categories.workspace = true
description = "Procedural macro for constructing structs with lazily initialized fields, builder pattern, and serde support with a focus on declarative syntax."
documentation = "https://docs.rs"
edition.workspace = true
exclude.workspace = true
keywords.workspace = true
Expand Down Expand Up @@ -38,3 +39,6 @@
diagnostics = ["fieldx_derive/diagnostics"]
send_guard = ["parking_lot/send_guard"]
serde = ["fieldx_derive/serde", "parking_lot/serde", "dep:serde"]

[package.metadata.docs.rs]
all-features = true
7 changes: 5 additions & 2 deletions fieldx/src/async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@ mod fxlock;
mod fxproxy;

pub use fxlock::FXRwLockAsync;
pub use fxproxy::{FXBuilderFallible, FXBuilderInfallible, FXProxyAsync, FXWrLockGuardAsync};
pub use tokio::sync::{RwLock, RwLockMappedWriteGuard, RwLockReadGuard, RwLockWriteGuard};
#[doc(hidden)]
pub use fxproxy::{FXBuilderFallible, FXBuilderInfallible};
pub use fxproxy::{FXProxyAsync, FXWrLockGuardAsync};
// #[doc(hidden)]
// pub use tokio::sync::{RwLock, RwLockMappedWriteGuard, RwLockReadGuard, RwLockWriteGuard};
8 changes: 7 additions & 1 deletion fieldx/src/async/fxlock.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use std::{borrow::Borrow, fmt, fmt::Debug, ops::Deref};
pub use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};

/// Lock-protected container
///
/// This is a wrapper around [`RwLock`] sync primitive. It provides safe means of cloning the lock
/// and the data it protects. No other additional functionality is provided.
#[derive(Default)]
pub struct FXRwLockAsync<T>(RwLock<T>);

Expand All @@ -15,10 +19,12 @@ impl<T> FXRwLockAsync<T> {
self.0.into_inner()
}

/// Delegates to [`RwLock::read()`]
pub async fn read(&self) -> RwLockReadGuard<T> {
self.0.read().await
}

/// Delegates to [`RwLock::write()`]
pub async fn write(&self) -> RwLockWriteGuard<T> {
self.0.write().await
}
Expand Down
30 changes: 17 additions & 13 deletions fieldx/src/async/fxproxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ where

/// Write-lock returned by [`FXProxyAsync::write`] method
///
/// This type, in cooperation with the [`FXProxyAsync`] type, takes care of safely updating lazy field status when data is
/// being stored.
/// This type, in cooperation with the [`FXProxyAsync`] type, takes care of safely updating lazy field status when data
/// is being stored.
pub struct FXWrLockGuardAsync<'a, B>
where
B: FXBuilderWrapperAsync,
Expand Down Expand Up @@ -144,8 +144,8 @@ where
self.is_set_raw().load(Ordering::SeqCst)
}

/// Initialize the field without obtaining the lock. Note though that if the lock is already owned this method will
/// wait for it to be released.
/// Initialize the field without obtaining the lock by calling code. _Note_ though that internally the lock is still
/// required.
pub async fn lazy_init<'a>(&'a self, owner: &B::Owner) {
let _ = self.read_or_init(owner).await;
}
Expand All @@ -165,35 +165,39 @@ where
Ok(guard)
}

/// Since the container guarantees that reading from it initializes the wrapped value, this method provides
/// semit-direct access to it without the [`Option`] wrapper.
/// Lazy-initialize the field if necessary and return lock read guard for the inner value.
///
/// Panics if fallible field builder returns an error.
pub async fn read<'a>(&'a self, owner: &B::Owner) -> RwLockReadGuard<'a, B::Value> {
RwLockReadGuard::map(
RwLockWriteGuard::downgrade(self.read_or_init(owner).await.unwrap()),
|data: &Option<B::Value>| data.as_ref().unwrap(),
)
}

/// Since the container guarantees that reading from it initializes the wrapped value, this method provides
/// semit-direct mutable access to it without the [`Option`] wrapper.
/// Lazy-initialize the field if necessary and return lock write guard for the inner value.
///
/// Panics if fallible field builder returns an error.
pub async fn read_mut<'a>(&'a self, owner: &B::Owner) -> RwLockMappedWriteGuard<'a, B::Value> {
RwLockWriteGuard::map(
self.read_or_init(owner).await.unwrap(),
|data: &mut Option<B::Value>| data.as_mut().unwrap(),
)
}

/// Since the container guarantees that reading from it initializes the wrapped value, this method provides
/// semit-direct access to it without the [`Option`] wrapper.
/// Lazy-initialize the field if necessary and return lock read guard for the inner value.
///
/// Return the same error, as fallible field builder if it errors out.
pub async fn try_read<'a>(&'a self, owner: &B::Owner) -> Result<RwLockReadGuard<'a, B::Value>, B::Error> {
Ok(RwLockReadGuard::map(
RwLockWriteGuard::downgrade(self.read_or_init(owner).await?),
|data: &Option<B::Value>| data.as_ref().unwrap(),
))
}

/// Since the container guarantees that reading from it initializes the wrapped value, this method provides
/// semit-direct mutable access to it without the [`Option`] wrapper.
/// Lazy-initialize the field if necessary and return lock write guard for the inner value.
///
/// Return the same error, as fallible field builder if it errors out.
pub async fn try_read_mut<'a>(
&'a self,
owner: &B::Owner,
Expand All @@ -204,7 +208,7 @@ where
))
}

/// Provides write-lock to directly store the value.
/// Provides write-lock to directly store the value. Never calls the lazy builder.
pub async fn write<'a>(&'a self) -> FXWrLockGuardAsync<'a, B> {
FXWrLockGuardAsync::<'a, B>::new(self.value.write().await, self)
}
Expand Down
Loading

0 comments on commit 2879b2c

Please sign in to comment.