mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 14:18:04 +08:00
Make Resource aware of its own hash (#4187)
* Fix future message handler field name * Add Resource::hash() * Move all remaining resource types from core-types to graphene-resources * Review
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -4361,6 +4361,7 @@ dependencies = [
|
||||
"futures",
|
||||
"glam",
|
||||
"graphene-hash",
|
||||
"graphene-resource",
|
||||
"image",
|
||||
"kurbo",
|
||||
"ndarray",
|
||||
|
||||
@@ -15,7 +15,7 @@ impl Editor {
|
||||
graphene_std::uuid::set_uuid_seed(uuid_random_seed);
|
||||
|
||||
let mut dispatcher = Dispatcher::new(resource_storage);
|
||||
dispatcher.message_handlers.async_message_handler.set_wake(wake);
|
||||
dispatcher.message_handlers.future_message_handler.set_wake(wake);
|
||||
application_io.inject_resource_proxy(dispatcher.message_handlers.resource_storage_message_handler.resources());
|
||||
crate::node_graph_executor::replace_application_io(application_io);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ pub struct Dispatcher {
|
||||
pub struct DispatcherMessageHandlers {
|
||||
animation_message_handler: AnimationMessageHandler,
|
||||
app_window_message_handler: AppWindowMessageHandler,
|
||||
pub(crate) async_message_handler: FutureMessageHandler,
|
||||
pub(crate) future_message_handler: FutureMessageHandler,
|
||||
broadcast_message_handler: BroadcastMessageHandler,
|
||||
clipboard_message_handler: ClipboardMessageHandler,
|
||||
color_picker_message_handler: ColorPickerMessageHandler,
|
||||
@@ -127,7 +127,7 @@ impl Dispatcher {
|
||||
|
||||
// Drain async results into the queue before processing the new message.
|
||||
let mut async_results = VecDeque::new();
|
||||
self.message_handlers.async_message_handler.drain_results(&mut async_results);
|
||||
self.message_handlers.future_message_handler.drain_results(&mut async_results);
|
||||
if !async_results.is_empty() {
|
||||
Self::schedule_execution(&mut self.message_queues, true, async_results);
|
||||
}
|
||||
@@ -182,7 +182,7 @@ impl Dispatcher {
|
||||
self.message_handlers.app_window_message_handler.process_message(message, &mut queue, ());
|
||||
}
|
||||
Message::Future(message) => {
|
||||
self.message_handlers.async_message_handler.process_message(message, &mut queue, FutureMessageContext {});
|
||||
self.message_handlers.future_message_handler.process_message(message, &mut queue, FutureMessageContext {});
|
||||
}
|
||||
Message::Broadcast(message) => self.message_handlers.broadcast_message_handler.process_message(message, &mut queue, ()),
|
||||
Message::Clipboard(message) => self.message_handlers.clipboard_message_handler.process_message(message, &mut queue, ()),
|
||||
|
||||
@@ -53,7 +53,7 @@ impl MmapResourceStorage {
|
||||
|
||||
let path = self.path_for(hash);
|
||||
let mmap = Self::open_mmap(&path)?;
|
||||
let resource = Resource::new(MmappedBytes(mmap));
|
||||
let resource = Resource::new_unchecked(MmappedBytes(mmap), *hash);
|
||||
|
||||
self.cache.write().unwrap_or_else(|poisoned| poisoned.into_inner()).insert(*hash, resource.clone());
|
||||
Some(resource)
|
||||
|
||||
@@ -81,7 +81,7 @@ impl ResourceStorage for OpfsResourceStorage {
|
||||
let mut bytes = None;
|
||||
if !guard.cache.contains_key(&hash) {
|
||||
let resource_bytes = Arc::<[u8]>::from(data);
|
||||
guard.cache.insert(hash, Resource::new(resource_bytes.clone()));
|
||||
guard.cache.insert(hash, Resource::new_unchecked(resource_bytes.clone(), hash));
|
||||
bytes = Some(resource_bytes);
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ async fn read_from_opfs(inner: Arc<Mutex<Inner>>, hash: ResourceHash) -> Option<
|
||||
return None;
|
||||
}
|
||||
|
||||
let resource = Resource::new(bytes);
|
||||
let resource = Resource::new_unchecked(bytes, hash);
|
||||
let mut guard = inner.lock().unwrap();
|
||||
if let Some(resource) = guard.cache.get(&hash) {
|
||||
return Some(resource.clone());
|
||||
|
||||
@@ -9,10 +9,7 @@ use std::time::Duration;
|
||||
use text_nodes::FontCache;
|
||||
use vector_types::vector::style::RenderMode;
|
||||
|
||||
pub mod resource {
|
||||
pub use core_types::resource::*;
|
||||
pub use graphene_resource::*;
|
||||
}
|
||||
pub use graphene_resource as resource;
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, DynAny)]
|
||||
|
||||
@@ -11,7 +11,6 @@ pub mod misc;
|
||||
pub mod ops;
|
||||
pub mod registry;
|
||||
pub mod render_complexity;
|
||||
pub mod resource;
|
||||
pub mod transform;
|
||||
pub mod uuid;
|
||||
pub mod value;
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
use dyn_any::DynAny;
|
||||
use graphene_hash::CacheHash;
|
||||
use std::hash::Hash;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, DynAny)]
|
||||
pub struct Resource {
|
||||
inner: Arc<dyn AsRef<[u8]> + Send + Sync>,
|
||||
}
|
||||
|
||||
impl Resource {
|
||||
pub fn new<T: AsRef<[u8]> + Send + Sync + 'static>(data: T) -> Self {
|
||||
Self { inner: Arc::new(data) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Resource> for Arc<dyn AsRef<[u8]> + Send + Sync> {
|
||||
fn from(val: &Resource) -> Self {
|
||||
val.inner.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Resource {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
(*self.inner).as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Resource {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
(*self.inner).as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Resource {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Resource").field("len", &self.len()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Resource {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_ref() == other.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl CacheHash for Resource {
|
||||
fn cache_hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.as_ref().hash(state);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +1,68 @@
|
||||
use core_types::resource::Resource;
|
||||
use core_types::{CacheHash, graphene_hash};
|
||||
use dyn_any::DynAny;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::future::Future;
|
||||
use std::hash::Hash;
|
||||
use std::ops::Deref;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait LoadResource: Send + Sync {
|
||||
fn load(&self, hash: ResourceHash) -> ResourceFuture;
|
||||
#[derive(Clone, DynAny)]
|
||||
pub struct Resource {
|
||||
inner: Arc<dyn AsRef<[u8]> + Send + Sync>,
|
||||
hash: ResourceHash,
|
||||
}
|
||||
|
||||
pub type ResourceFuture = Pin<Box<dyn Future<Output = Option<Resource>> + Send + 'static>>;
|
||||
impl Resource {
|
||||
pub fn new<T: AsRef<[u8]> + Send + Sync + 'static>(data: T) -> Self {
|
||||
let hash = ResourceHash::from(data.as_ref());
|
||||
Self { inner: Arc::new(data), hash }
|
||||
}
|
||||
|
||||
pub trait ResourceStorage: LoadResource {
|
||||
fn store(&mut self, data: &[u8]) -> ResourceHash;
|
||||
fn contains(&mut self, hash: &ResourceHash) -> bool;
|
||||
fn garbage_collect(&mut self, used: &[ResourceHash]);
|
||||
}
|
||||
pub fn new_unchecked<T: AsRef<[u8]> + Send + Sync + 'static>(data: T, hash: ResourceHash) -> Self {
|
||||
Self { inner: Arc::new(data), hash }
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, graphene_hash::CacheHash, PartialOrd, Ord, DynAny)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct ResourceId(u64);
|
||||
|
||||
impl ResourceId {
|
||||
pub fn new() -> Self {
|
||||
Self(core_types::uuid::generate_uuid())
|
||||
pub fn hash(&self) -> ResourceHash {
|
||||
self.hash
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ResourceId {
|
||||
impl From<&Resource> for Arc<dyn AsRef<[u8]> + Send + Sync> {
|
||||
fn from(val: &Resource) -> Self {
|
||||
val.inner.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Resource {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &[u8] {
|
||||
(*self.inner).as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Resource {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
(*self.inner).as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Resource {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
f.debug_struct("Resource").field("len", &self.len()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Resource {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.hash == other.hash
|
||||
}
|
||||
}
|
||||
|
||||
impl CacheHash for Resource {
|
||||
fn cache_hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.hash.cache_hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,8 +100,8 @@ impl From<&ResourceHash> for String {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ResourceHash {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
impl std::fmt::Display for ResourceHash {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&String::from(self))
|
||||
}
|
||||
}
|
||||
@@ -111,8 +141,8 @@ pub enum ResourceHashParseError {
|
||||
InvalidCharacter { byte: u8, position: usize },
|
||||
}
|
||||
|
||||
impl fmt::Display for ResourceHashParseError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
impl std::fmt::Display for ResourceHashParseError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::InvalidLength { found } => write!(f, "resource hash must be 64 hex characters, got {found}"),
|
||||
Self::InvalidCharacter { byte, position } => write!(f, "resource hash contains non-hex byte {byte:#04x} at position {position}"),
|
||||
@@ -149,7 +179,7 @@ impl<'de> serde::Deserialize<'de> for ResourceHash {
|
||||
impl<'de> serde::de::Visitor<'de> for ResourceHashVisitor {
|
||||
type Value = ResourceHash;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a 64-character hex string or 32 raw bytes")
|
||||
}
|
||||
|
||||
@@ -185,6 +215,35 @@ impl CacheHash for ResourceHash {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait LoadResource: Send + Sync {
|
||||
fn load(&self, hash: ResourceHash) -> ResourceFuture;
|
||||
}
|
||||
|
||||
pub type ResourceFuture = Pin<Box<dyn Future<Output = Option<Resource>> + Send + 'static>>;
|
||||
|
||||
pub trait ResourceStorage: LoadResource {
|
||||
fn store(&mut self, data: &[u8]) -> ResourceHash;
|
||||
fn contains(&mut self, hash: &ResourceHash) -> bool;
|
||||
fn garbage_collect(&mut self, used: &[ResourceHash]);
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, graphene_hash::CacheHash, PartialOrd, Ord, DynAny)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct ResourceId(u64);
|
||||
|
||||
impl ResourceId {
|
||||
pub fn new() -> Self {
|
||||
Self(core_types::uuid::generate_uuid())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ResourceId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub type DataSources = Box<[DataSource]>;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
||||
@@ -17,6 +17,7 @@ std = [
|
||||
"serde",
|
||||
"dep:core-types",
|
||||
"dep:dyn-any",
|
||||
"dep:graphene-resource",
|
||||
"dep:graphene-hash",
|
||||
"dep:raster-types",
|
||||
"dep:vector-types",
|
||||
@@ -43,6 +44,7 @@ node-macro = { workspace = true }
|
||||
# Local std dependencies
|
||||
dyn-any = { workspace = true, optional = true }
|
||||
core-types = { workspace = true, optional = true }
|
||||
graphene-resource = { workspace = true, optional = true }
|
||||
graphene-hash = { workspace = true, optional = true }
|
||||
raster-types = { workspace = true, optional = true }
|
||||
vector-types = { workspace = true, optional = true }
|
||||
|
||||
@@ -5,11 +5,11 @@ use core_types::color::{Alpha, AlphaMut, Channel, LinearChannel, Luminance, RGBM
|
||||
use core_types::context::{Ctx, ExtractFootprint};
|
||||
use core_types::list::{Item, List};
|
||||
use core_types::math::bbox::Bbox;
|
||||
use core_types::resource::Resource;
|
||||
use core_types::transform::Transform;
|
||||
use dyn_any::DynAny;
|
||||
use fastnoise_lite;
|
||||
use glam::{DAffine2, DVec2, Vec2};
|
||||
use graphene_resource::Resource;
|
||||
use rand::prelude::*;
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
use raster_types::Image;
|
||||
|
||||
Reference in New Issue
Block a user