Skip to content

Commit

Permalink
OwnedRefFrozenRef
Browse files Browse the repository at this point in the history
Summary:
Like `OwnedFrozenRef`, but cheaper (`&FrozenHeapRef` instead of `FrozenHeapRef`).

Used in D61059023.

Reviewed By: JakobDegen

Differential Revision: D61059024

fbshipit-source-id: c33c57914c23cb384ec77ed0b4fb2f390e37000c
  • Loading branch information
stepancheg authored and facebook-github-bot committed Aug 19, 2024
1 parent 6d8d8fe commit 240f5d8
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 1 deletion.
1 change: 1 addition & 0 deletions starlark-rust/starlark/src/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
pub use layout::alloc_static_simple::AllocStaticSimple;
pub use owned_frozen_ref::OwnedFrozenRef;
pub use owned_frozen_ref::OwnedRefFrozenRef;
pub use starlark_derive::starlark_attrs;
pub use starlark_derive::starlark_value;
pub use starlark_derive::AllocFrozenValue;
Expand Down
6 changes: 6 additions & 0 deletions starlark-rust/starlark/src/values/owned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use crate::values::FrozenHeap;
use crate::values::FrozenHeapRef;
use crate::values::FrozenValue;
use crate::values::FrozenValueTyped;
use crate::values::OwnedRefFrozenRef;
use crate::values::StarlarkValue;
use crate::values::Value;

Expand Down Expand Up @@ -267,6 +268,11 @@ impl<T: StarlarkValue<'static>> OwnedFrozenValueTyped<T> {
}
}

/// Convert to borrowed ref.
pub fn as_owned_ref_frozen_ref(&self) -> OwnedRefFrozenRef<'_, T> {
unsafe { OwnedRefFrozenRef::new_unchecked(self.value.as_ref(), &self.owner) }
}

/// Convert to an owned ref.
pub fn into_owned_frozen_ref(self) -> OwnedFrozenRef<T> {
// SAFETY: Heap matches the value
Expand Down
96 changes: 95 additions & 1 deletion starlark-rust/starlark/src/values/owned_frozen_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,29 @@
* limitations under the License.
*/

use std::convert::Infallible;
use std::fmt;
use std::fmt::Formatter;
use std::mem;
use std::ops::Deref;

use allocative::Allocative;
use dupe::Clone_;
use dupe::Copy_;
use dupe::Dupe;
use dupe::Dupe_;

use crate::values::FrozenHeap;
use crate::values::FrozenHeapRef;
use crate::values::FrozenRef;

/// A reference to a value stored in a frozen heap with a reference to the heap.
#[derive(Copy_, Clone_, Dupe_)]
pub struct OwnedRefFrozenRef<'f, T: ?Sized + 'static> {
owner: &'f FrozenHeapRef,
value: FrozenRef<'f, T>,
}

/// Same as a `FrozenRef`, but it keeps itself alive by storing a reference to the owning heap.
///
/// Usually constructed from an `OwnedFrozenValueTyped`.
Expand All @@ -35,6 +48,79 @@ pub struct OwnedFrozenRef<T: ?Sized + 'static> {
value: FrozenRef<'static, T>,
}

impl<'f, T: ?Sized> OwnedRefFrozenRef<'f, T> {
/// Create a new `OwnedRefFrozenRef` pointing at the given value.
pub unsafe fn new_unchecked(
value: &'f T,
owner: &'f FrozenHeapRef,
) -> OwnedRefFrozenRef<'f, T> {
OwnedRefFrozenRef {
owner,
value: FrozenRef::new(value),
}
}

/// Owner heap.
pub fn owner(&self) -> &'f FrozenHeapRef {
self.owner
}

/// Return a reference to the underlying value.
pub fn as_ref(self) -> &'f T {
self.value.as_ref()
}

/// Add a reference to a new heap, and return the pointer with the lifetime of the new heap.
pub fn add_heap_ref<'v>(self, heap: &'v FrozenHeap) -> &'v T {
heap.add_reference(self.owner);
unsafe { mem::transmute::<&'f T, &'v T>(self.value.as_ref()) }
}

/// Convert heap pointer to an owned one.
pub fn to_owned(self) -> OwnedFrozenRef<T> {
OwnedFrozenRef {
owner: self.owner.dupe(),
value: unsafe { mem::transmute::<FrozenRef<'f, T>, FrozenRef<'static, T>>(self.value) },
}
}

/// Fallible map the reference to another one.
pub fn try_map_result<F, U: ?Sized, E>(self, f: F) -> Result<OwnedRefFrozenRef<'f, U>, E>
where
F: FnOnce(&'f T) -> Result<&'f U, E>,
{
Ok(OwnedRefFrozenRef {
owner: self.owner,
value: FrozenRef::new(f(self.value.as_ref())?),
})
}

/// Apply a function to the underlying value. Projection operation.
pub fn map<F, U: ?Sized>(self, f: F) -> OwnedRefFrozenRef<'f, U>
where
F: FnOnce(&'f T) -> &'f U,
{
match self.try_map_result(|x| Ok(f(x))) {
Ok(x) => x,
Err(e) => {
let e: Infallible = e;
match e {}
}
}
}

/// Optionally map the reference to another one.
pub fn try_map_option<F, U: ?Sized>(self, f: F) -> Option<OwnedRefFrozenRef<'f, U>>
where
F: FnOnce(&'f T) -> Option<&'f U>,
{
match self.try_map_result(|x| f(x).ok_or(())) {
Ok(x) => Some(x),
Err(()) => None,
}
}
}

impl<T: ?Sized> OwnedFrozenRef<T> {
/// Creates a new `OwnedFrozenRef` pointing at the given value.
///
Expand All @@ -48,9 +134,17 @@ impl<T: ?Sized> OwnedFrozenRef<T> {
}
}

/// Borrow.
pub fn as_owned_ref_frozen_ref(&self) -> OwnedRefFrozenRef<'_, T> {
OwnedRefFrozenRef {
owner: &self.owner,
value: self.value,
}
}

/// Returns a reference to the underlying value.
pub fn as_ref<'a>(&'a self) -> &'a T {
self.value.as_ref()
self.as_owned_ref_frozen_ref().as_ref()
}

/// Converts `self` into a new reference that points at something reachable from the previous.
Expand Down

0 comments on commit 240f5d8

Please sign in to comment.