Improve the ergonomics of creating local buffers (#10347)
This PR renames `language::Buffer::new` to `language::Buffer::local` and simplifies its interface. Instead of taking a replica id (which should always be 0 for the local case) and a `BufferId`, which was awkward and verbose to construct, it simply takes text and a `cx`. It uses the `cx` to derive a `BufferId` from the `EntityId` associated with the `cx`, which should always be positive based on the following analysis... We convert the entity id to a u64 using this method on `EntityId`, which is defined by macros in the `slotmap` crate: ```rust pub fn as_ffi(self) -> u64 { (u64::from(self.version.get()) << 32) | u64::from(self.idx) } ``` If you look at the type of `version` in `KeyData`, it is non-zero: ```rust #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct KeyData { idx: u32, version: NonZeroU32, } ``` This commit also adds `Context::reserve_model` and `Context::insert_model` to determine a model's entity ID before it is created, which we need in order to assign a `BufferId` in the background when loading a buffer asynchronously. Release Notes: - N/A --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
This commit is contained in:
parent
664efef76b
commit
7abb63cfda
31 changed files with 376 additions and 519 deletions
|
@ -32,9 +32,9 @@ use crate::{
|
|||
AppMetadata, AssetCache, AssetSource, BackgroundExecutor, ClipboardItem, Context,
|
||||
DispatchPhase, DisplayId, Entity, EventEmitter, ForegroundExecutor, Global, KeyBinding, Keymap,
|
||||
Keystroke, LayoutId, Menu, PathPromptOptions, Pixels, Platform, PlatformDisplay, Point,
|
||||
PromptBuilder, PromptHandle, PromptLevel, Render, RenderablePromptHandle, SharedString,
|
||||
SubscriberSet, Subscription, SvgRenderer, Task, TextSystem, View, ViewContext, Window,
|
||||
WindowAppearance, WindowContext, WindowHandle, WindowId,
|
||||
PromptBuilder, PromptHandle, PromptLevel, Render, RenderablePromptHandle, Reservation,
|
||||
SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextSystem, View, ViewContext,
|
||||
Window, WindowAppearance, WindowContext, WindowHandle, WindowId,
|
||||
};
|
||||
|
||||
mod async_context;
|
||||
|
@ -1251,6 +1251,22 @@ impl Context for AppContext {
|
|||
})
|
||||
}
|
||||
|
||||
fn reserve_model<T: 'static>(&mut self) -> Self::Result<Reservation<T>> {
|
||||
Reservation(self.entities.reserve())
|
||||
}
|
||||
|
||||
fn insert_model<T: 'static>(
|
||||
&mut self,
|
||||
reservation: Reservation<T>,
|
||||
build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T,
|
||||
) -> Self::Result<Model<T>> {
|
||||
self.update(|cx| {
|
||||
let slot = reservation.0;
|
||||
let entity = build_model(&mut ModelContext::new(cx, slot.downgrade()));
|
||||
cx.entities.insert(slot, entity)
|
||||
})
|
||||
}
|
||||
|
||||
/// Updates the entity referenced by the given model. The function is passed a mutable reference to the
|
||||
/// entity along with a `ModelContext` for the entity.
|
||||
fn update_model<T: 'static, R>(
|
||||
|
@ -1266,6 +1282,18 @@ impl Context for AppContext {
|
|||
})
|
||||
}
|
||||
|
||||
fn read_model<T, R>(
|
||||
&self,
|
||||
handle: &Model<T>,
|
||||
read: impl FnOnce(&T, &AppContext) -> R,
|
||||
) -> Self::Result<R>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
let entity = self.entities.read(handle);
|
||||
read(entity, self)
|
||||
}
|
||||
|
||||
fn update_window<T, F>(&mut self, handle: AnyWindowHandle, update: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
|
||||
|
@ -1295,18 +1323,6 @@ impl Context for AppContext {
|
|||
})
|
||||
}
|
||||
|
||||
fn read_model<T, R>(
|
||||
&self,
|
||||
handle: &Model<T>,
|
||||
read: impl FnOnce(&T, &AppContext) -> R,
|
||||
) -> Self::Result<R>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
let entity = self.entities.read(handle);
|
||||
read(entity, self)
|
||||
}
|
||||
|
||||
fn read_window<T, R>(
|
||||
&self,
|
||||
window: &WindowHandle<T>,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
AnyView, AnyWindowHandle, AppCell, AppContext, BackgroundExecutor, BorrowAppContext, Context,
|
||||
DismissEvent, FocusableView, ForegroundExecutor, Global, Model, ModelContext, Render, Result,
|
||||
Task, View, ViewContext, VisualContext, WindowContext, WindowHandle,
|
||||
DismissEvent, FocusableView, ForegroundExecutor, Global, Model, ModelContext, Render,
|
||||
Reservation, Result, Task, View, ViewContext, VisualContext, WindowContext, WindowHandle,
|
||||
};
|
||||
use anyhow::{anyhow, Context as _};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
|
@ -35,6 +35,28 @@ impl Context for AsyncAppContext {
|
|||
Ok(app.new_model(build_model))
|
||||
}
|
||||
|
||||
fn reserve_model<T: 'static>(&mut self) -> Result<Reservation<T>> {
|
||||
let app = self
|
||||
.app
|
||||
.upgrade()
|
||||
.ok_or_else(|| anyhow!("app was released"))?;
|
||||
let mut app = app.borrow_mut();
|
||||
Ok(app.reserve_model())
|
||||
}
|
||||
|
||||
fn insert_model<T: 'static>(
|
||||
&mut self,
|
||||
reservation: Reservation<T>,
|
||||
build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T,
|
||||
) -> Result<Model<T>> {
|
||||
let app = self
|
||||
.app
|
||||
.upgrade()
|
||||
.ok_or_else(|| anyhow!("app was released"))?;
|
||||
let mut app = app.borrow_mut();
|
||||
Ok(app.insert_model(reservation, build_model))
|
||||
}
|
||||
|
||||
fn update_model<T: 'static, R>(
|
||||
&mut self,
|
||||
handle: &Model<T>,
|
||||
|
@ -278,6 +300,19 @@ impl Context for AsyncWindowContext {
|
|||
self.window.update(self, |_, cx| cx.new_model(build_model))
|
||||
}
|
||||
|
||||
fn reserve_model<T: 'static>(&mut self) -> Result<Reservation<T>> {
|
||||
self.window.update(self, |_, cx| cx.reserve_model())
|
||||
}
|
||||
|
||||
fn insert_model<T: 'static>(
|
||||
&mut self,
|
||||
reservation: Reservation<T>,
|
||||
build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T,
|
||||
) -> Self::Result<Model<T>> {
|
||||
self.window
|
||||
.update(self, |_, cx| cx.insert_model(reservation, build_model))
|
||||
}
|
||||
|
||||
fn update_model<T: 'static, R>(
|
||||
&mut self,
|
||||
handle: &Model<T>,
|
||||
|
@ -287,13 +322,6 @@ impl Context for AsyncWindowContext {
|
|||
.update(self, |_, cx| cx.update_model(handle, update))
|
||||
}
|
||||
|
||||
fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
|
||||
{
|
||||
self.app.update_window(window, update)
|
||||
}
|
||||
|
||||
fn read_model<T, R>(
|
||||
&self,
|
||||
handle: &Model<T>,
|
||||
|
@ -305,6 +333,13 @@ impl Context for AsyncWindowContext {
|
|||
self.app.read_model(handle, read)
|
||||
}
|
||||
|
||||
fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
|
||||
{
|
||||
self.app.update_window(window, update)
|
||||
}
|
||||
|
||||
fn read_window<T, R>(
|
||||
&self,
|
||||
window: &WindowHandle<T>,
|
||||
|
|
|
@ -9,6 +9,7 @@ use std::{
|
|||
hash::{Hash, Hasher},
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
num::NonZeroU64,
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering::SeqCst},
|
||||
Arc, Weak,
|
||||
|
@ -31,6 +32,11 @@ impl From<u64> for EntityId {
|
|||
}
|
||||
|
||||
impl EntityId {
|
||||
/// Converts this entity id to a [NonZeroU64]
|
||||
pub fn as_non_zero_u64(self) -> NonZeroU64 {
|
||||
NonZeroU64::new(self.0.as_ffi()).unwrap()
|
||||
}
|
||||
|
||||
/// Converts this entity id to a [u64]
|
||||
pub fn as_u64(self) -> u64 {
|
||||
self.0.as_ffi()
|
||||
|
@ -128,14 +134,16 @@ impl EntityMap {
|
|||
|
||||
dropped_entity_ids
|
||||
.into_iter()
|
||||
.map(|entity_id| {
|
||||
.filter_map(|entity_id| {
|
||||
let count = ref_counts.counts.remove(entity_id).unwrap();
|
||||
debug_assert_eq!(
|
||||
count.load(SeqCst),
|
||||
0,
|
||||
"dropped an entity that was referenced"
|
||||
);
|
||||
(entity_id, self.entities.remove(entity_id).unwrap())
|
||||
// If the EntityId was allocated with `Context::reserve`,
|
||||
// the entity may not have been inserted.
|
||||
Some((entity_id, self.entities.remove(entity_id)?))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
AnyView, AnyWindowHandle, AppContext, AsyncAppContext, Context, Effect, Entity, EntityId,
|
||||
EventEmitter, Model, Subscription, Task, View, WeakModel, WindowContext, WindowHandle,
|
||||
EventEmitter, Model, Reservation, Subscription, Task, View, WeakModel, WindowContext,
|
||||
WindowHandle,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
|
@ -229,6 +230,18 @@ impl<'a, T> Context for ModelContext<'a, T> {
|
|||
self.app.new_model(build_model)
|
||||
}
|
||||
|
||||
fn reserve_model<U: 'static>(&mut self) -> Reservation<U> {
|
||||
self.app.reserve_model()
|
||||
}
|
||||
|
||||
fn insert_model<U: 'static>(
|
||||
&mut self,
|
||||
reservation: Reservation<U>,
|
||||
build_model: impl FnOnce(&mut ModelContext<'_, U>) -> U,
|
||||
) -> Self::Result<Model<U>> {
|
||||
self.app.insert_model(reservation, build_model)
|
||||
}
|
||||
|
||||
fn update_model<U: 'static, R>(
|
||||
&mut self,
|
||||
handle: &Model<U>,
|
||||
|
@ -237,13 +250,6 @@ impl<'a, T> Context for ModelContext<'a, T> {
|
|||
self.app.update_model(handle, update)
|
||||
}
|
||||
|
||||
fn update_window<R, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> R,
|
||||
{
|
||||
self.app.update_window(window, update)
|
||||
}
|
||||
|
||||
fn read_model<U, R>(
|
||||
&self,
|
||||
handle: &Model<U>,
|
||||
|
@ -255,6 +261,13 @@ impl<'a, T> Context for ModelContext<'a, T> {
|
|||
self.app.read_model(handle, read)
|
||||
}
|
||||
|
||||
fn update_window<R, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> R,
|
||||
{
|
||||
self.app.update_window(window, update)
|
||||
}
|
||||
|
||||
fn read_window<U, R>(
|
||||
&self,
|
||||
window: &WindowHandle<U>,
|
||||
|
|
|
@ -42,6 +42,20 @@ impl Context for TestAppContext {
|
|||
app.new_model(build_model)
|
||||
}
|
||||
|
||||
fn reserve_model<T: 'static>(&mut self) -> Self::Result<crate::Reservation<T>> {
|
||||
let mut app = self.app.borrow_mut();
|
||||
app.reserve_model()
|
||||
}
|
||||
|
||||
fn insert_model<T: 'static>(
|
||||
&mut self,
|
||||
reservation: crate::Reservation<T>,
|
||||
build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T,
|
||||
) -> Self::Result<Model<T>> {
|
||||
let mut app = self.app.borrow_mut();
|
||||
app.insert_model(reservation, build_model)
|
||||
}
|
||||
|
||||
fn update_model<T: 'static, R>(
|
||||
&mut self,
|
||||
handle: &Model<T>,
|
||||
|
@ -803,6 +817,18 @@ impl Context for VisualTestContext {
|
|||
self.cx.new_model(build_model)
|
||||
}
|
||||
|
||||
fn reserve_model<T: 'static>(&mut self) -> Self::Result<crate::Reservation<T>> {
|
||||
self.cx.reserve_model()
|
||||
}
|
||||
|
||||
fn insert_model<T: 'static>(
|
||||
&mut self,
|
||||
reservation: crate::Reservation<T>,
|
||||
build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T,
|
||||
) -> Self::Result<Model<T>> {
|
||||
self.cx.insert_model(reservation, build_model)
|
||||
}
|
||||
|
||||
fn update_model<T, R>(
|
||||
&mut self,
|
||||
handle: &Model<T>,
|
||||
|
|
|
@ -165,6 +165,19 @@ pub trait Context {
|
|||
build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T,
|
||||
) -> Self::Result<Model<T>>;
|
||||
|
||||
/// Reserve a slot for a model to be inserted later.
|
||||
/// The returned [Reservation] allows you to obtain the [EntityId] for the future model.
|
||||
fn reserve_model<T: 'static>(&mut self) -> Self::Result<Reservation<T>>;
|
||||
|
||||
/// Insert a new model in the app context based on a [Reservation] previously obtained from [`reserve_model`].
|
||||
///
|
||||
/// [`reserve_model`]: Self::reserve_model
|
||||
fn insert_model<T: 'static>(
|
||||
&mut self,
|
||||
reservation: Reservation<T>,
|
||||
build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T,
|
||||
) -> Self::Result<Model<T>>;
|
||||
|
||||
/// Update a model in the app context.
|
||||
fn update_model<T, R>(
|
||||
&mut self,
|
||||
|
@ -198,6 +211,17 @@ pub trait Context {
|
|||
T: 'static;
|
||||
}
|
||||
|
||||
/// Returned by [Context::reserve_model] to later be passed to [Context::insert_model].
|
||||
/// Allows you to obtain the [EntityId] for a model before it is created.
|
||||
pub struct Reservation<T>(pub(crate) Slot<T>);
|
||||
|
||||
impl<T: 'static> Reservation<T> {
|
||||
/// Returns the [EntityId] that will be associated with the model once it is inserted.
|
||||
pub fn entity_id(&self) -> EntityId {
|
||||
self.0.entity_id()
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait is used for the different visual contexts in GPUI that
|
||||
/// require a window to be present.
|
||||
pub trait VisualContext: Context {
|
||||
|
|
|
@ -1830,6 +1830,18 @@ impl Context for WindowContext<'_> {
|
|||
self.entities.insert(slot, model)
|
||||
}
|
||||
|
||||
fn reserve_model<T: 'static>(&mut self) -> Self::Result<crate::Reservation<T>> {
|
||||
self.app.reserve_model()
|
||||
}
|
||||
|
||||
fn insert_model<T: 'static>(
|
||||
&mut self,
|
||||
reservation: crate::Reservation<T>,
|
||||
build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T,
|
||||
) -> Self::Result<Model<T>> {
|
||||
self.app.insert_model(reservation, build_model)
|
||||
}
|
||||
|
||||
fn update_model<T: 'static, R>(
|
||||
&mut self,
|
||||
model: &Model<T>,
|
||||
|
@ -1844,18 +1856,6 @@ impl Context for WindowContext<'_> {
|
|||
result
|
||||
}
|
||||
|
||||
fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
|
||||
{
|
||||
if window == self.window.handle {
|
||||
let root_view = self.window.root_view.clone().unwrap();
|
||||
Ok(update(root_view, self))
|
||||
} else {
|
||||
window.update(self.app, update)
|
||||
}
|
||||
}
|
||||
|
||||
fn read_model<T, R>(
|
||||
&self,
|
||||
handle: &Model<T>,
|
||||
|
@ -1868,6 +1868,18 @@ impl Context for WindowContext<'_> {
|
|||
read(entity, &*self.app)
|
||||
}
|
||||
|
||||
fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
|
||||
{
|
||||
if window == self.window.handle {
|
||||
let root_view = self.window.root_view.clone().unwrap();
|
||||
Ok(update(root_view, self))
|
||||
} else {
|
||||
window.update(self.app, update)
|
||||
}
|
||||
}
|
||||
|
||||
fn read_window<T, R>(
|
||||
&self,
|
||||
window: &WindowHandle<T>,
|
||||
|
@ -2478,6 +2490,18 @@ impl<V> Context for ViewContext<'_, V> {
|
|||
self.window_cx.new_model(build_model)
|
||||
}
|
||||
|
||||
fn reserve_model<T: 'static>(&mut self) -> Self::Result<crate::Reservation<T>> {
|
||||
self.window_cx.reserve_model()
|
||||
}
|
||||
|
||||
fn insert_model<T: 'static>(
|
||||
&mut self,
|
||||
reservation: crate::Reservation<T>,
|
||||
build_model: impl FnOnce(&mut ModelContext<'_, T>) -> T,
|
||||
) -> Self::Result<Model<T>> {
|
||||
self.window_cx.insert_model(reservation, build_model)
|
||||
}
|
||||
|
||||
fn update_model<T: 'static, R>(
|
||||
&mut self,
|
||||
model: &Model<T>,
|
||||
|
@ -2486,13 +2510,6 @@ impl<V> Context for ViewContext<'_, V> {
|
|||
self.window_cx.update_model(model, update)
|
||||
}
|
||||
|
||||
fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
|
||||
{
|
||||
self.window_cx.update_window(window, update)
|
||||
}
|
||||
|
||||
fn read_model<T, R>(
|
||||
&self,
|
||||
handle: &Model<T>,
|
||||
|
@ -2504,6 +2521,13 @@ impl<V> Context for ViewContext<'_, V> {
|
|||
self.window_cx.read_model(handle, read)
|
||||
}
|
||||
|
||||
fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
|
||||
{
|
||||
self.window_cx.update_window(window, update)
|
||||
}
|
||||
|
||||
fn read_window<T, R>(
|
||||
&self,
|
||||
window: &WindowHandle<T>,
|
||||
|
|
|
@ -264,6 +264,18 @@ impl<'a> Context for ElementContext<'a> {
|
|||
self.cx.new_model(build_model)
|
||||
}
|
||||
|
||||
fn reserve_model<T: 'static>(&mut self) -> Self::Result<crate::Reservation<T>> {
|
||||
self.cx.reserve_model()
|
||||
}
|
||||
|
||||
fn insert_model<T: 'static>(
|
||||
&mut self,
|
||||
reservation: crate::Reservation<T>,
|
||||
build_model: impl FnOnce(&mut crate::ModelContext<'_, T>) -> T,
|
||||
) -> Self::Result<crate::Model<T>> {
|
||||
self.cx.insert_model(reservation, build_model)
|
||||
}
|
||||
|
||||
fn update_model<T, R>(
|
||||
&mut self,
|
||||
handle: &crate::Model<T>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue