# WrapIt
`wrapit` is a small Rust library that wraps any variable using interior mutability to allow mutation through shared references.
This crate provides a generic Wrapper<T> and SyncWrapper<T> types for single-threaded use, which allows:
- Mutable access to a value through a shared reference.
- Convenient cloning and sharing via Arc.
- Read, reset, and functional mapping of the inner value.
**Note**: This crate uses RefCell or Mutex for interior mutability. Using RefCell is not thread-safe because it does **not** implement the Send and Sync traits. Concurrent access across threads will ONLY compile, if you use SyncWrapper<T> type.
---
## Installation
You can install `wrapit` either from Crates.io or directly from the Git repository.
### Installing from Crates.io
1. Open your `Cargo.toml` file.
2. Add `wrapit` to your dependencies:
```toml
[dependencies]
wrapit = "0.2.0"
```
OR do;
```toml
cargo add wrapit
```
from your project folder or directory.
### Installing directly from Git
1. Open your `Cargo.toml` file.
2. Add `wrapit` as a dependency using the Git repository URL:
```toml
[dependencies]
wrapit = { git = "https://github.com/2teez/wrapit.git" }
```
3. In your Rust code, import the wrapper:
```rust
use wrapit::Wrapper; // Not thread-safe
use wrapit::SyncWrapper; // thread-safe
```
OR
```rust
use wrapit::{Wrapper, SyncWrapper};
```
## Description
`wrapit` allows you to wrap any value and mutate it through a shared reference, similar to JavaScript or Python variables. You can modify the value using the **_reset_** method and read it using **_get_**, without needing the **_mut_** keyword on the wrapper itself.
`wrapit` provides two wrapper types: `Wrapper` and `SyncWrapper`. Both share a similar API and serve the same purpose of encapsulating a value for controlled mutation.
The key difference lies in their safety guarantees:
* `Wrapper` uses non-thread-safe interior mutability and exposes a `borrow` method.
* `SyncWrapper` is thread-safe and exposes a `lock` method for synchronized access.
```javascript
// in javascript
const langs = ["java", "clojure", "lua"];
langs.push("swift");
console.log(langs);
```
However in rust, you will have to use the `mut` keyword with the variable like so:
```rust
let mut langs = vec!["java", "clojure", "lua"];
langs.push("swift");
println!("{:?}", langs);
```
using `wrapit`, do this:
```rust
use wrapit::Wrapper;
let langs = vec!["java", "clojure", "lua"]; // immutable
let wrapper = Wrapper::new(langs);
// changed the variable content without the `mut` keyword
wrapper.reset(vec!["java", "clojure", "lua", "swift"]);
println!("{:?}", wrapper);
```
OR
```rust
use std::thread;
use wrapit::SyncWrapper;
// Create a thread-safe wrapper for an integer
let counter = SyncWrapper::new(0);
// Read-only access using map
});
// Modify the value safely using lock
{
let mut guard = counter.lock(); // no need for `mut` on counter itself
*guard = 1;
println!("Locked value: {:?}", *guard);
} // lock released here
// Using a thread to read the value without mut
let counter_clone = counter.clone();
})
.join()
.unwrap();
// Replace the value using reset
counter.reset(42);
println!("After reset, value: {}", counter.get());
}
```
## wrapit::Wrapper Methods
1. new
```rust
pub fn new(data: T) -> Self
```
>
> - Creates a new Wrapper<T> containing data.
> - Allocates the value inside RefCell and wraps it in Arc.
- No runtime panic.
### Example:
```rust
let wrapper = Wrapper::new(42);
```
2. reset
```rust
pub fn reset(&self, ndata: T) -> &Self
```
>
> - Replaces the inner value with ndata.
> - Returns a reference to self for method chaining.
> - Panics at runtime if any active borrow exists (e.g., if .borrow() has been called and not dropped).
### Example:
```rust
wrapper.reset(100);
```
3. get
```rust
pub fn get(&self) -> T
```
>
> - Returns a clone of the inner value.
> - Uses immutable borrow (borrow()) internally.
> - Panics if a mutable borrow is active.
### Example:
```rust
let value = wrapper.get();
```
4. borrow
```rust
pub fn borrow(&self) -> std::cell::Ref<'_, T>
```
>
> - Returns a Ref<T>, a smart pointer for immutable access.
> - Automatically releases the borrow when dropped.
> - Panics if a mutable borrow is active.
## Example:
```rust
let value_ref = wrapper.borrow();
println!("{}", *value_ref);
```
5. map
```rust
pub fn map<F, U>(&self, f: F) -> U
where
F: FnOnce(&T) -> U,
```
>
> - Applies a function f to the inner value.
> - Returns the function’s result.
> - Panics if a mutable borrow exists while calling this method.
## Example:
```rust
### Summary of Runtime Panics
reset() | Active immutable borrow exists
get() | Active mutable borrow exists
borrow() | Active mutable borrow exists
map() | Active mutable borrow exists
> - These panics are enforced at runtime by *RefCell*.
## Usage Example
```rust
use wrapped::wrapped::Wrapper;
let w = Wrapper::new(String::from("Rust"));
// Read value
assert_eq!(w.get(), "Rust");
// Mutate value
w.reset(String::from("C++"));
assert_eq!(w.get(), "C++");
// Borrow inner value
let val = w.borrow();
println!("Value = {}", *val);
// Map function
```
## Notes
> - This Wrapper is not thread-safe. If you want wrapper which is thread-safe use SyncWrapper instead.
> - All borrows are checked at runtime using RefCell.
> - Use .borrow() and .borrow_mut() carefully to avoid panics.
> - Cloning the Wrapper shares the same underlying value.
## wrapit::SyncWrapper Methods
6. new
```rust
pub fn new(data: T) -> Self
```
>
> - Creates a new thread-safe SyncWrapper containing the provided value.
> - Allocates the value inside RefCell and wraps it in Arc.
> - No runtime panic.
## Example:
```rust
use wrapit::SyncWrapper;
let wrapper = SyncWrapper::new("clojure");
assert_eq!(wrapper.get(), "clojure");
```
7. reset
```rust
pub fn reset(&self, ndata: T) -> &Self
```
> - The `reset` method of `SyncWrapper` replaces the current value inside the wrapper with a new one.
> - Acquires a lock on the internal `Mutex<T>`.
> - Replaces the current value with `ndata`.
> - Automatically releases the lock when the operation completes.
> - Panics if the mutex is poisoned (i.e., another thread panicked while holding the lock).
## Example
```rust
use wrapit::SyncWrapper;
fn main() {
let wrapper = SyncWrapper::new(10);
// Reset the value
wrapper.reset(42);
// Verify
assert_eq!(wrapper.get(), 42);
// Method chaining
wrapper.reset(100).reset(200);
assert_eq!(wrapper.get(), 200);
}
```
## Notes
* `reset` does **not** give direct mutable access to the internal value.
* To modify the value directly, use `lock()` instead.
* Useful for simple replacement of the value without explicit locking.
* Works safely across threads due to internal `Mutex`.
8. get
```rust
pub fn get(&self) -> T
```
> - The `get` method of `SyncWrapper` returns a clone of the current value stored inside the wrapper.
> - Acquires a lock on the internal `Mutex<T>`.
> - Clones and returns the value.
> - Automatically releases the lock when done.
> - Panics if the mutex is poisoned (i.e., another thread panicked while holding the lock).
## Example
```rust
use wrapit::SyncWrapper;
fn main() {
let wrapper = SyncWrapper::new(10);
// Read the value
let val = wrapper.get();
assert_eq!(val, 10);
// The wrapper is still accessible after getting the value
wrapper.reset(42);
assert_eq!(wrapper.get(), 42);
}
```
## Notes
* `get` provides a safe, read-only snapshot of the value.
* The returned value is a clone; modifying it does not affect the wrapper.
* To modify the value directly, use `lock()` or `reset()`.
9. lock
```rust
pub fn lock(&self) -> std::sync::MutexGuard<'_, T>
```
> - The `lock` method of `SyncWrapper` provides mutable access to the value inside the wrapper by returning a `MutexGuard`.
> - Acquires a lock on the internal `Mutex<T>`.
> - Returns a `MutexGuard` that can be used to read or modify the value.
> - Automatically releases the lock when the guard goes out of scope.
> - Panics if the mutex is poisoned (i.e., another thread panicked while holding the lock).
## Example
```rust
use wrapit::SyncWrapper;
fn main() {
let wrapper = SyncWrapper::new(vec![1, 2, 3]);
{
let mut guard = wrapper.lock();
guard.push(4); // modify directly
println!("Locked value: {:?}", *guard);
} // lock released here automatically
assert_eq!(wrapper.get(), vec![1, 2, 3, 4]);
}
```
## Notes
* Use `lock()` when you need direct mutable access to the value.
* The lock is released automatically when the `MutexGuard` goes out of scope.
* Safe to call from multiple threads; each will block until the mutex is available.
* Avoid holding the lock across long operations or thread joins to prevent deadlocks.
10. map
```rust
pub fn map<F, U>(&self, f: F) -> U
where
F: FnOnce(&T) -> U
```
> - The `map` method of `SyncWrapper` allows you to apply a function to the wrapped value without exposing the `MutexGuard` directly.
> - Acquires a lock on the internal `Mutex<T>`.
> - Calls the provided function `f` with a reference to the value.
> - Automatically releases the lock after the function call.
> - Panics if the mutex is poisoned (i.e., another thread panicked while holding the lock).
## Example
```rust
use wrapit::SyncWrapper;
fn main() {
let wrapper = SyncWrapper::new(10);
// Read-only computation using map
let doubled = wrapper.map(|x| x * 2);
assert_eq!(doubled, 20);
// Original value remains unchanged
assert_eq!(wrapper.get(), 10);
// Can also read a vector safely
let w = SyncWrapper::new(vec![1, 2, 3]);
let length = w.map(|v| v.len());
assert_eq!(length, 3);
}
```
## Notes
* `map` is useful when you want temporary, controlled access to the value without exposing the `MutexGuard`.
* The lock is released immediately after the closure finishes.
* Safe to use concurrently across multiple threads.
* Ideal for read-only operations or computations that do not need to mutate the value directly.
## Versioning:
`0.1.0` - wrapit with non thread-safe wrapper.
`0.1.1` - README.md file wordings changed.
`0.2.0` - wrapit with thread-safe wrapper included, with the README.md file updated to reflect the change.