Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ edition = "2018"
crossbeam-channel = "0.4.4"
log = { version = "0.4.6", features = ["std"] }
time = "0.1.35"
lazy_format = "2.0.3"
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,41 @@ fn main() {
```

More examples can be found under `examples` directory.

## Handling Owned Formatting Arguments

The standard `std::fmt::Arguments` type in Rust is tied to the lifetime of the data being formatted. This makes it unsuitable for scenarios where the formatted arguments need to be stored or sent across threads (i.e., require a `'static` lifetime).

For these situations, you can use the `lazy_format` crate. It allows you to create formatting objects that capture their arguments (by moving or cloning them). If all captured arguments are themselves owned and `'static`, the resulting `lazy_format` object can also be `'static`.

**Example:**

```rust
use lazy_format::lazy_format;
use std::fmt::Display;
use std::thread;

fn create_owned_formatter(name: String, count: i32) -> Box<dyn Display + Send + 'static> {
Box::new(lazy_format!("User: {}, Count: {}", name, count))
}

fn main() {
let name = String::from("Alice");
let formatter = create_owned_formatter(name, 42);

let handle = thread::spawn(move || {
// This formatter can be sent to another thread
println!("{}", formatter); // Outputs: "User: Alice, Count: 42"
});
handle.join().unwrap();
}
```

First, add `lazy_format` to your `Cargo.toml`:

```toml
[dependencies]
lazy_format = "2.0.3" # Use the latest version
```

This approach provides a flexible way to handle formatting needs where lifetimes would otherwise be an issue.
28 changes: 28 additions & 0 deletions examples/owned_format.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use lazy_format::lazy_format;
use std::fmt::Display;
use std::thread;

fn main() {
let owned_string = String::from("world");
let number = 42;

// Create a lazy_format object that captures owned data.
// This object itself should be Send + 'static.
let formatter: Box<dyn Display + Send + 'static> =
Box::new(lazy_format!("Hello, {}! The number is {}.", owned_string, number));

// Demonstrate that it can be sent to another thread.
let handle = thread::spawn(move || {
// Format the object in the other thread.
let formatted_string = formatter.to_string();
println!("From thread: {}", formatted_string);
formatted_string
});

let result_from_thread = handle.join().expect("Thread panicked");

println!("In main thread, got back: {}", result_from_thread);

assert_eq!(result_from_thread, "Hello, world! The number is 42.");
println!("Successfully created and used an owned formatter across threads!");
}
60 changes: 60 additions & 0 deletions tests/owned_format_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use lazy_format::lazy_format;
use std::fmt::Display;
use std::thread;

#[test]
fn test_owned_format_across_threads() {
let owned_string = String::from("Rustacean");
let value = 100;

// Create a lazy_format object capturing owned data.
// Ensure it's Send + 'static by boxing it.
let formatter: Box<dyn Display + Send + 'static> =
Box::new(lazy_format!("Greetings, {}! Your score is {}.", owned_string, value));

// Move to another thread and format.
let handle = thread::spawn(move || {
formatter.to_string()
});

let result_from_thread = handle.join().expect("Thread panicked during test");

assert_eq!(result_from_thread, "Greetings, Rustacean! Your score is 100.");
}

#[test]
fn test_owned_format_static_lifetime() {
// This test demonstrates that if all inputs are 'static, the formatter can be 'static.
fn create_static_formatter() -> Box<dyn Display + Send + 'static> {
Box::new(lazy_format!("This is a static message from {}.", "static data"))
}

let formatter = create_static_formatter();

// Move to another thread
let handle = thread::spawn(move || {
formatter.to_string()
});

let result = handle.join().unwrap();
assert_eq!(result, "This is a static message from static data.");
}

#[test]
fn test_format_with_owned_moved_value() {
let my_data = String::from("owned and moved");

// my_data is moved into the formatter
let formatter: Box<dyn Display + Send + 'static> =
Box::new(lazy_format!("Data: {}", my_data));

// If my_data was not moved, this would be a compile error:
// drop(my_data); // uncommenting this should cause a compile error if lazy_format doesn't take ownership

let handle = thread::spawn(move || {
formatter.to_string()
});

let result = handle.join().unwrap();
assert_eq!(result, "Data: owned and moved");
}
Loading