mirror of
https://github.com/salsa-rs/salsa.git
synced 2024-10-23 04:46:35 +00:00
introduce Slot trait
This commit is contained in:
parent
33a99da476
commit
db8d64faa6
4 changed files with 34 additions and 45 deletions
|
@ -7,6 +7,7 @@ use crate::id::AsId;
|
|||
use crate::ingredient::fmt_index;
|
||||
use crate::key::DependencyIndex;
|
||||
use crate::plumbing::Jar;
|
||||
use crate::table::Slot;
|
||||
use crate::zalsa::IngredientIndex;
|
||||
use crate::zalsa_local::QueryOrigin;
|
||||
use crate::{Database, DatabaseKeyIndex, Id};
|
||||
|
@ -19,7 +20,7 @@ pub trait Configuration: Sized + 'static {
|
|||
const DEBUG_NAME: &'static str;
|
||||
|
||||
/// The type of data being interned
|
||||
type Data<'db>: InternedData + Send + Sync;
|
||||
type Data<'db>: InternedData;
|
||||
|
||||
/// The end user struct
|
||||
type Struct<'db>: Copy;
|
||||
|
@ -36,8 +37,8 @@ pub trait Configuration: Sized + 'static {
|
|||
fn deref_struct(s: Self::Struct<'_>) -> Id;
|
||||
}
|
||||
|
||||
pub trait InternedData: Sized + Eq + Hash + Clone {}
|
||||
impl<T: Eq + Hash + Clone> InternedData for T {}
|
||||
pub trait InternedData: Sized + Eq + Hash + Clone + Sync + Send {}
|
||||
impl<T: Eq + Hash + Clone + Sync + Send> InternedData for T {}
|
||||
|
||||
pub struct JarImpl<C: Configuration> {
|
||||
phantom: PhantomData<C>,
|
||||
|
@ -67,8 +68,7 @@ pub struct Value<C>
|
|||
where
|
||||
C: Configuration,
|
||||
{
|
||||
id: Id,
|
||||
fields: C::Data<'static>,
|
||||
data: C::Data<'static>,
|
||||
}
|
||||
|
||||
impl<C: Configuration> Default for JarImpl<C> {
|
||||
|
@ -147,7 +147,13 @@ where
|
|||
dashmap::mapref::entry::Entry::Vacant(entry) => {
|
||||
let zalsa = db.zalsa();
|
||||
let table = zalsa.table();
|
||||
let next_id = zalsa_local.allocate(table, self.ingredient_index, internal_data);
|
||||
let next_id = zalsa_local.allocate(
|
||||
table,
|
||||
self.ingredient_index,
|
||||
Value::<C> {
|
||||
data: internal_data,
|
||||
},
|
||||
);
|
||||
entry.insert(next_id);
|
||||
C::struct_from_id(next_id)
|
||||
}
|
||||
|
@ -158,8 +164,8 @@ where
|
|||
/// Rarely used since end-users generally carry a struct with a pointer directly
|
||||
/// to the interned item.
|
||||
pub fn data<'db>(&'db self, db: &'db dyn Database, id: Id) -> &'db C::Data<'db> {
|
||||
let internal_data = db.zalsa().table().get::<C::Data<'static>>(id);
|
||||
unsafe { self.from_internal_data(internal_data) }
|
||||
let internal_data = db.zalsa().table().get::<Value<C>>(id);
|
||||
unsafe { self.from_internal_data(&internal_data.data) }
|
||||
}
|
||||
|
||||
/// Lookup the fields from an interned struct.
|
||||
|
@ -259,26 +265,4 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<C> Value<C>
|
||||
where
|
||||
C: Configuration,
|
||||
{
|
||||
pub fn data(&self) -> &C::Data<'_> {
|
||||
// SAFETY: The lifetime of `self` is tied to the interning ingredient;
|
||||
// we never remove data without an `&mut self` access to the interning ingredient.
|
||||
unsafe { self.to_self_ref(&self.fields) }
|
||||
}
|
||||
|
||||
unsafe fn to_self_ref<'db>(&'db self, fields: &'db C::Data<'static>) -> &'db C::Data<'db> {
|
||||
unsafe { std::mem::transmute(fields) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> AsId for Value<C>
|
||||
where
|
||||
C: Configuration,
|
||||
{
|
||||
fn as_id(&self) -> Id {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
impl<C> Slot for Value<C> where C: Configuration {}
|
||||
|
|
25
src/table.rs
25
src/table.rs
|
@ -6,6 +6,7 @@ use std::{
|
|||
|
||||
use append_only_vec::AppendOnlyVec;
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use memo::MemoTable;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use crate::{zalsa::transmute_data_ptr, Id, IngredientIndex};
|
||||
|
@ -24,7 +25,7 @@ pub(crate) trait TablePage: Any + Send + Sync {
|
|||
fn hidden_type_name(&self) -> &'static str;
|
||||
}
|
||||
|
||||
pub(crate) struct Page<T: Any + Send + Sync> {
|
||||
pub(crate) struct Page<T: Slot> {
|
||||
/// The ingredient for elements on this page.
|
||||
#[allow(dead_code)] // pretty sure we'll need this
|
||||
ingredient: IngredientIndex,
|
||||
|
@ -47,11 +48,13 @@ pub(crate) struct Page<T: Any + Send + Sync> {
|
|||
data: Vec<UnsafeCell<T>>,
|
||||
}
|
||||
|
||||
unsafe impl<T: Any + Send + Sync> Send for Page<T> {}
|
||||
pub(crate) trait Slot: Any + Send + Sync {}
|
||||
|
||||
unsafe impl<T: Any + Send + Sync> Sync for Page<T> {}
|
||||
unsafe impl<T: Slot> Send for Page<T> {}
|
||||
|
||||
impl<T: Any + Send + Sync> RefUnwindSafe for Page<T> {}
|
||||
unsafe impl<T: Slot> Sync for Page<T> {}
|
||||
|
||||
impl<T: Slot> RefUnwindSafe for Page<T> {}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PageIndex(usize);
|
||||
|
@ -68,29 +71,29 @@ impl Default for Table {
|
|||
}
|
||||
|
||||
impl Table {
|
||||
pub fn get<T: Any + Send + Sync>(&self, id: Id) -> &T {
|
||||
pub fn get<T: Slot>(&self, id: Id) -> &T {
|
||||
let (page, slot) = split_id(id);
|
||||
let page_ref = self.page::<T>(page);
|
||||
page_ref.get(slot)
|
||||
}
|
||||
|
||||
pub fn get_raw<T: Any + Send + Sync>(&self, id: Id) -> *mut T {
|
||||
pub fn get_raw<T: Slot>(&self, id: Id) -> *mut T {
|
||||
let (page, slot) = split_id(id);
|
||||
let page_ref = self.page::<T>(page);
|
||||
page_ref.get_raw(slot)
|
||||
}
|
||||
|
||||
pub fn page<T: Any + Send + Sync>(&self, page: PageIndex) -> &Page<T> {
|
||||
pub fn page<T: Slot>(&self, page: PageIndex) -> &Page<T> {
|
||||
self.pages[page.0].assert_type::<Page<T>>()
|
||||
}
|
||||
|
||||
pub fn push_page<T: Any + Send + Sync>(&self, ingredient: IngredientIndex) -> PageIndex {
|
||||
pub fn push_page<T: Slot>(&self, ingredient: IngredientIndex) -> PageIndex {
|
||||
let page = Box::new(<Page<T>>::new(ingredient));
|
||||
PageIndex(self.pages.push(page))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Any + Send + Sync> Page<T> {
|
||||
impl<T: Slot> Page<T> {
|
||||
fn new(ingredient: IngredientIndex) -> Self {
|
||||
let mut data = Vec::with_capacity(PAGE_LEN);
|
||||
unsafe {
|
||||
|
@ -137,13 +140,13 @@ impl<T: Any + Send + Sync> Page<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Any + Send + Sync> TablePage for Page<T> {
|
||||
impl<T: Slot> TablePage for Page<T> {
|
||||
fn hidden_type_name(&self) -> &'static str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Any + Send + Sync> Drop for Page<T> {
|
||||
impl<T: Slot> Drop for Page<T> {
|
||||
fn drop(&mut self) {
|
||||
// Free `self.data` and the data within: to do this, we swap it out with an empty vector
|
||||
// and then convert it from a `Vec<UnsafeCell<T>>` with partially uninitialized values
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::{
|
|||
plumbing::ZalsaLocal,
|
||||
runtime::StampedValue,
|
||||
salsa_struct::SalsaStructInDb,
|
||||
table::Table,
|
||||
table::{Slot, Table},
|
||||
zalsa::{IngredientIndex, Zalsa},
|
||||
zalsa_local::QueryOrigin,
|
||||
Database, Durability, Event, Id, Revision,
|
||||
|
@ -634,3 +634,5 @@ where
|
|||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Slot for Value<C> where C: Configuration {}
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::key::DatabaseKeyIndex;
|
|||
use crate::key::DependencyIndex;
|
||||
use crate::runtime::StampedValue;
|
||||
use crate::table::PageIndex;
|
||||
use crate::table::Slot;
|
||||
use crate::table::Table;
|
||||
use crate::tracked_struct::Disambiguator;
|
||||
use crate::tracked_struct::KeyStruct;
|
||||
|
@ -18,7 +19,6 @@ use crate::Event;
|
|||
use crate::EventKind;
|
||||
use crate::Id;
|
||||
use crate::Revision;
|
||||
use std::any::Any;
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -54,7 +54,7 @@ impl ZalsaLocal {
|
|||
/// Allocate a new id in `table` for the given ingredient
|
||||
/// storing `value`. Remembers the most recent page from this
|
||||
/// thread and attempts to reuse it.
|
||||
pub(crate) fn allocate<'t, T: Any + Send + Sync>(
|
||||
pub(crate) fn allocate<'t, T: Slot>(
|
||||
&self,
|
||||
table: &Table,
|
||||
ingredient: IngredientIndex,
|
||||
|
|
Loading…
Reference in a new issue