Skip to content

Improve some rough edges. #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
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
22 changes: 17 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
//!
//! # Example of usage.
//!
//! ```
//! ```rust
//! # #[cfg(feature = "alloc")]
//! # {
//! use static_rc::StaticRc;
//!
//! type Full<T> = StaticRc<T, 3, 3>;
Expand Down Expand Up @@ -38,6 +40,7 @@
//! assert_eq!("Hello, world!", &*full);
//!
//! // Finally, the value is dropped when `full` is.
//! # }
//! ```
//!
//! # Options
Expand All @@ -53,16 +56,25 @@

// Regular features
#![cfg_attr(not(test), no_std)]

// Nightly features
#![cfg_attr(feature = "compile-time-ratio", allow(incomplete_features))]
// https://github.com/rust-lang/rust/issues/76560
#![cfg_attr(feature = "compile-time-ratio", feature(generic_const_exprs))]
// https://github.com/rust-lang/rust/issues/79024
#![cfg_attr(feature = "nightly-async-iterator", feature(async_iterator))]
// https://github.com/rust-lang/rust/issues/18598
#![cfg_attr(feature = "nightly-coerce-unsized", feature(coerce_unsized))]
#![cfg_attr(feature = "nightly-dispatch-from-dyn", feature(dispatch_from_dyn))]
#![cfg_attr(any(feature = "nightly-dispatch-from-dyn", feature = "nightly-coerce-unsized"), feature(unsize))]
#![cfg_attr(
any(
feature = "nightly-dispatch-from-dyn",
feature = "nightly-coerce-unsized"
),
feature(unsize)
)]
// https://github.com/rust-lang/rust/issues/43122
#![cfg_attr(feature = "nightly-generator-trait", feature(generator_trait))]

// https://doc.rust-lang.org/core/ops/trait.DispatchFromDyn.html
#![cfg_attr(feature = "nightly-dispatch-from-dyn", feature(dispatch_from_dyn))]
// Lints
#![deny(missing_docs)]

Expand Down
163 changes: 79 additions & 84 deletions src/lift.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
//! Lifting allows tying the note when linear or affine types -- such as `StaticRc` -- are used to implement cyclic
//! data-structures such as linked-lists.

use core::{
mem::ManuallyDrop,
ptr,
};
use core::{mem::ManuallyDrop, ptr};

/// Lifts `root` into the slot provided by `fun`; returns the previous value of the slot, if any.
///
Expand Down Expand Up @@ -103,108 +100,106 @@ unsafe fn replace<T>(dest: *mut ManuallyDrop<T>, src: *const ManuallyDrop<T>) ->

#[cfg(test)]
mod tests {
use core::{cell, mem};

use std::{cell, mem};
use super::*;

use super::*;
// Example from https://github.com/matthieu-m/static-rc/issues/14 by @noamtashma.
//
// Using `UnsafeCell` instead of `GhostCell` to avoid 3rd-party dependency.
fn lift_self_impl(cell_ref: &cell::UnsafeCell<Box<i32>>) -> &mut cell::UnsafeCell<Box<i32>> {
// cell_ref.borrow_mut(token) with GhostCell.
let borrowed: &mut Box<i32> = unsafe { &mut *cell_ref.get() };

// Example from https://github.com/matthieu-m/static-rc/issues/14 by @noamtashma.
//
// Using `UnsafeCell` instead of `GhostCell` to avoid 3rd-party dependency.
fn lift_self_impl(cell_ref: &cell::UnsafeCell<Box<i32>>) -> &mut cell::UnsafeCell<Box<i32>> {
// cell_ref.borrow_mut(token) with GhostCell.
let borrowed: &mut Box<i32> = unsafe { &mut *cell_ref.get() };
// GhostCell::from_mut
let transmuted: &mut cell::UnsafeCell<Box<i32>> = unsafe { mem::transmute(borrowed) };

// GhostCell::from_mut
let transmuted: &mut cell::UnsafeCell<Box<i32>> = unsafe { mem::transmute(borrowed) };
transmuted
}

transmuted
}
#[test]
fn lift_self() {
let cell = cell::UnsafeCell::new(Box::new(7));

#[test]
fn lift_self() {
let cell = cell::UnsafeCell::new(Box::new(7));
lift(cell, lift_self_impl);
}

lift(cell, lift_self_impl);
}
#[test]
fn lift_with_self() {
let cell = cell::UnsafeCell::new(Box::new(7));

#[test]
fn lift_with_self() {
let cell = cell::UnsafeCell::new(Box::new(7));
lift_with(cell, &(), |cell_ref, _| lift_self_impl(cell_ref));
}

lift_with(cell, &(), |cell_ref, _| lift_self_impl(cell_ref));
}
#[test]
fn lift_with_mut_self() {
let cell = cell::UnsafeCell::new(Box::new(7));

#[test]
fn lift_with_mut_self() {
let cell = cell::UnsafeCell::new(Box::new(7));
lift_with_mut(cell, &mut (), |cell_ref, _| lift_self_impl(cell_ref));
}

lift_with_mut(cell, &mut (), |cell_ref, _| lift_self_impl(cell_ref));
}
// Example from https://users.rust-lang.org/t/can-you-break-the-lift/58858/19 by @steffahn.
//
// Arranged and annotated by yours truly.
struct Struct;

// Example from https://users.rust-lang.org/t/can-you-break-the-lift/58858/19 by @steffahn.
//
// Arranged and annotated by yours truly.
struct Struct;
#[allow(clippy::mut_from_ref)]
trait LeakBorrow {
fn foo(&self) -> &mut Box<dyn LeakBorrow>;
}

#[allow(clippy::mut_from_ref)]
trait LeakBorrow {
fn foo(&self) -> &mut Box<dyn LeakBorrow>;
}
impl LeakBorrow for cell::RefCell<Box<dyn LeakBorrow>> {
fn foo(&self) -> &mut Box<dyn LeakBorrow> {
let refmut: cell::RefMut<'_, _> = self.borrow_mut();
let refmut_refmut: &mut cell::RefMut<'_, _> = Box::leak(Box::new(refmut));
will_leak(&*refmut_refmut);

impl LeakBorrow for cell::RefCell<Box<dyn LeakBorrow>> {
fn foo(&self) -> &mut Box<dyn LeakBorrow> {
let refmut: cell::RefMut<'_, _> = self.borrow_mut();
let refmut_refmut: &mut cell::RefMut<'_, _> = Box::leak(Box::new(refmut));
will_leak(&*refmut_refmut);
&mut **refmut_refmut
}
}

&mut **refmut_refmut
impl LeakBorrow for Struct {
fn foo(&self) -> &mut Box<dyn LeakBorrow> {
unimplemented!()
}
}
}

impl LeakBorrow for Struct {
fn foo(&self) -> &mut Box<dyn LeakBorrow> {
unimplemented!()
#[test]
fn lift_leak_borrow() {
let root = Box::new(Struct) as Box<dyn LeakBorrow>;
let root = Box::new(cell::RefCell::new(root)) as Box<dyn LeakBorrow>;
lift(root, |b| b.foo());
}
}

#[test]
fn lift_leak_borrow() {
let root = Box::new(Struct) as Box<dyn LeakBorrow>;
let root = Box::new(cell::RefCell::new(root)) as Box<dyn LeakBorrow>;
lift(root, |b| b.foo());
}
#[test]
fn lift_with_leak_borrow() {
let root = Box::new(Struct) as Box<dyn LeakBorrow>;
let root = Box::new(cell::RefCell::new(root)) as Box<dyn LeakBorrow>;
lift_with(root, &(), |b, _| b.foo());
}

#[test]
fn lift_with_leak_borrow() {
let root = Box::new(Struct) as Box<dyn LeakBorrow>;
let root = Box::new(cell::RefCell::new(root)) as Box<dyn LeakBorrow>;
lift_with(root, &(), |b, _| b.foo());
}
#[test]
fn lift_with_mut_leak_borrow() {
let root = Box::new(Struct) as Box<dyn LeakBorrow>;
let root = Box::new(cell::RefCell::new(root)) as Box<dyn LeakBorrow>;
lift_with_mut(root, &mut (), |b, _| b.foo());
}

#[test]
fn lift_with_mut_leak_borrow() {
let root = Box::new(Struct) as Box<dyn LeakBorrow>;
let root = Box::new(cell::RefCell::new(root)) as Box<dyn LeakBorrow>;
lift_with_mut(root, &mut (), |b, _| b.foo());
}
// Indicates that the pointed to memory will be leaked, to avoid it being reported.
fn will_leak<T>(_t: &T) {
#[cfg(miri)]
{
unsafe { miri_static_root(_t as *const _ as *const u8) };
}
}

// Indicates that the pointed to memory will be leaked, to avoid it being reported.
fn will_leak<T>(_t: &T) {
#[cfg(miri)]
{
unsafe { miri_static_root(_t as *const _ as *const u8) };
extern "Rust" {
/// Miri-provided extern function to mark the block `ptr` points to as a "root"
/// for some static memory. This memory and everything reachable by it is not
/// considered leaking even if it still exists when the program terminates.
///
/// `ptr` has to point to the beginning of an allocated block.
fn miri_static_root(ptr: *const u8);
}
}

#[cfg(miri)]
extern "Rust" {
/// Miri-provided extern function to mark the block `ptr` points to as a "root"
/// for some static memory. This memory and everything reachable by it is not
/// considered leaking even if it still exists when the program terminates.
///
/// `ptr` has to point to the beginning of an allocated block.
fn miri_static_root(ptr: *const u8);
}

} // mod tests
Loading