Skip to content

Commit

Permalink
Add owner_with_lifetime example
Browse files Browse the repository at this point in the history
  • Loading branch information
Voultapher committed Nov 7, 2021
1 parent 82d10f0 commit 1fa78ef
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 4 deletions.
11 changes: 7 additions & 4 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ jobs:
cd examples
cargo run --verbose --bin fallible_dependent_construction
cargo run --verbose --bin lazy_ast
cargo run --verbose --bin owner_with_lifetime
- name: Build benchmarks
run: |
cd benchmarks
Expand Down Expand Up @@ -81,8 +82,9 @@ jobs:
- name: Run examples x86_64-unknown-linux-gnu
run: |
cd examples
cargo miri run --verbose --bin fallible_dependent_construction
cargo miri run --verbose --bin lazy_ast
cargo miri run --verbose --target x86_64-unknown-linux-gnu --bin fallible_dependent_construction
cargo miri run --verbose --target x86_64-unknown-linux-gnu --bin lazy_ast
cargo miri run --verbose --target x86_64-unknown-linux-gnu --bin owner_with_lifetime
- name: Run tests mips64-unknown-linux-gnuabi64
run: |
Expand All @@ -94,6 +96,7 @@ jobs:
- name: Run examples mips64-unknown-linux-gnuabi64
run: |
cd examples
cargo miri run --verbose --bin fallible_dependent_construction
cargo miri run --verbose --bin lazy_ast
cargo miri run --verbose --target mips64-unknown-linux-gnuabi64 --bin fallible_dependent_construction
cargo miri run --verbose --target mips64-unknown-linux-gnuabi64 --bin lazy_ast
cargo miri run --verbose --target mips64-unknown-linux-gnuabi64 --bin owner_with_lifetime
1 change: 1 addition & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
members = [
"fallible_dependent_construction",
"lazy_ast",
"owner_with_lifetime",
]
3 changes: 3 additions & 0 deletions examples/REAME.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ The advanced examples:
- [How to handle dependent construction that can fail](fallible_dependent_construction)

- [How to build a lazy AST with self_cell](lazy_ast)

- [How to use an owner type with lifetime](owner_with_lifetime)

10 changes: 10 additions & 0 deletions examples/owner_with_lifetime/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "owner_with_lifetime"
version = "0.1.0"
authors = ["Lukas Bergdoll <lukas.bergdoll@gmail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
self_cell = { path="../../"}
22 changes: 22 additions & 0 deletions examples/owner_with_lifetime/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# `owner_with_lifetime` Example

Here we want to optionally escape an input string and then compute an AST based
on this escaped string. This means we either borrow the 'input lifetime
reference or the function stack local owned string produced as result of
escaping the input. This can only be done with a self-referential struct, that
still is statically lifetime dependent on the input.

Run this example with `cargo run`, it should output:

```
input: "au bx"
not_escaped.borrow_dependent() -> ["au", "bx"]
input: "au bz"
escaping input (owned alloc)
escaped.borrow_dependent() -> ["az", "bz"]
```

Notice for the first input that contains an 'x' no escaping is done, so the
dummy AST is a Vec of pointers into the original input. The second time with
input "au bz" there is no 'x' so we need want to escape the input and build the
AST based of that as seen "az" instead of "au" in the input.
59 changes: 59 additions & 0 deletions examples/owner_with_lifetime/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// This example demonstrates a use-case where a lifetime in the owner is required.

use std::borrow::Cow;

use self_cell::self_cell;

type Ast<'a> = Vec<&'a str>;

self_cell!(
struct AstCell<'input> {
owner: Cow<'input, str>,

#[covariant]
dependent: Ast,
}
);

impl<'input> AstCell<'input> {
// Escape input if necessary before constructing AST.
fn from_un_escaped(input: &'input str) -> Self {
println!("input: {:?}", input);

let escaped_input = if input.contains("x") {
Cow::from(input)
} else {
println!("escaping input (owned alloc)");
let owned: String = input.replace('u', "z");
Cow::from(owned)
};

// This would be impossible without a self-referential struct.
// escaped_input could either be a pointer to the input or an owned
// string on stack.
// We only want to depend on the input lifetime and encapsulate the
// string escaping logic in a function. Which we can't do with
// vanilla Rust.
// Non self-referential version https://godbolt.org/z/3Pcc9a5za error.
Self::new(escaped_input, |escaped_input| {
// Dummy for expensive computation you don't want to redo.
escaped_input.split(' ').collect()
})
}
}

fn main() {
let not_escaped = AstCell::from_un_escaped("au bx");

println!(
"not_escaped.borrow_dependent() -> {:?}",
not_escaped.borrow_dependent()
);

let escaped = AstCell::from_un_escaped("au bz");

println!(
"escaped.borrow_dependent() -> {:?}",
escaped.borrow_dependent()
);
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@
//! - [How to build a lazy AST with
//! self_cell](https://github.com/Voultapher/self_cell/tree/main/examples/lazy_ast)
//!
//! - [How to use an owner type with
//! lifetime](https://github.com/Voultapher/self_cell/tree/main/examples/owner_with_lifetime)
//!
//! ### Min required rustc version
//!
//! By default the minimum required rustc version is 1.51.
Expand Down

0 comments on commit 1fa78ef

Please sign in to comment.