mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-27 15:38:11 +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:
Generated
+1
@@ -4361,6 +4361,7 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"glam",
|
"glam",
|
||||||
"graphene-hash",
|
"graphene-hash",
|
||||||
|
"graphene-resource",
|
||||||
"image",
|
"image",
|
||||||
"kurbo",
|
"kurbo",
|
||||||
"ndarray",
|
"ndarray",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ impl Editor {
|
|||||||
graphene_std::uuid::set_uuid_seed(uuid_random_seed);
|
graphene_std::uuid::set_uuid_seed(uuid_random_seed);
|
||||||
|
|
||||||
let mut dispatcher = Dispatcher::new(resource_storage);
|
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());
|
application_io.inject_resource_proxy(dispatcher.message_handlers.resource_storage_message_handler.resources());
|
||||||
crate::node_graph_executor::replace_application_io(application_io);
|
crate::node_graph_executor::replace_application_io(application_io);
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ pub struct Dispatcher {
|
|||||||
pub struct DispatcherMessageHandlers {
|
pub struct DispatcherMessageHandlers {
|
||||||
animation_message_handler: AnimationMessageHandler,
|
animation_message_handler: AnimationMessageHandler,
|
||||||
app_window_message_handler: AppWindowMessageHandler,
|
app_window_message_handler: AppWindowMessageHandler,
|
||||||
pub(crate) async_message_handler: FutureMessageHandler,
|
pub(crate) future_message_handler: FutureMessageHandler,
|
||||||
broadcast_message_handler: BroadcastMessageHandler,
|
broadcast_message_handler: BroadcastMessageHandler,
|
||||||
clipboard_message_handler: ClipboardMessageHandler,
|
clipboard_message_handler: ClipboardMessageHandler,
|
||||||
color_picker_message_handler: ColorPickerMessageHandler,
|
color_picker_message_handler: ColorPickerMessageHandler,
|
||||||
@@ -127,7 +127,7 @@ impl Dispatcher {
|
|||||||
|
|
||||||
// Drain async results into the queue before processing the new message.
|
// Drain async results into the queue before processing the new message.
|
||||||
let mut async_results = VecDeque::new();
|
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() {
|
if !async_results.is_empty() {
|
||||||
Self::schedule_execution(&mut self.message_queues, true, async_results);
|
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, ());
|
self.message_handlers.app_window_message_handler.process_message(message, &mut queue, ());
|
||||||
}
|
}
|
||||||
Message::Future(message) => {
|
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::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, ()),
|
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 path = self.path_for(hash);
|
||||||
let mmap = Self::open_mmap(&path)?;
|
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());
|
self.cache.write().unwrap_or_else(|poisoned| poisoned.into_inner()).insert(*hash, resource.clone());
|
||||||
Some(resource)
|
Some(resource)
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ impl ResourceStorage for OpfsResourceStorage {
|
|||||||
let mut bytes = None;
|
let mut bytes = None;
|
||||||
if !guard.cache.contains_key(&hash) {
|
if !guard.cache.contains_key(&hash) {
|
||||||
let resource_bytes = Arc::<[u8]>::from(data);
|
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);
|
bytes = Some(resource_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,7 +302,7 @@ async fn read_from_opfs(inner: Arc<Mutex<Inner>>, hash: ResourceHash) -> Option<
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let resource = Resource::new(bytes);
|
let resource = Resource::new_unchecked(bytes, hash);
|
||||||
let mut guard = inner.lock().unwrap();
|
let mut guard = inner.lock().unwrap();
|
||||||
if let Some(resource) = guard.cache.get(&hash) {
|
if let Some(resource) = guard.cache.get(&hash) {
|
||||||
return Some(resource.clone());
|
return Some(resource.clone());
|
||||||
|
|||||||
@@ -9,10 +9,7 @@ use std::time::Duration;
|
|||||||
use text_nodes::FontCache;
|
use text_nodes::FontCache;
|
||||||
use vector_types::vector::style::RenderMode;
|
use vector_types::vector::style::RenderMode;
|
||||||
|
|
||||||
pub mod resource {
|
pub use graphene_resource as resource;
|
||||||
pub use core_types::resource::*;
|
|
||||||
pub use graphene_resource::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "wgpu")]
|
#[cfg(feature = "wgpu")]
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, DynAny)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq, DynAny)]
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ pub mod misc;
|
|||||||
pub mod ops;
|
pub mod ops;
|
||||||
pub mod registry;
|
pub mod registry;
|
||||||
pub mod render_complexity;
|
pub mod render_complexity;
|
||||||
pub mod resource;
|
|
||||||
pub mod transform;
|
pub mod transform;
|
||||||
pub mod uuid;
|
pub mod uuid;
|
||||||
pub mod value;
|
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 core_types::{CacheHash, graphene_hash};
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub trait LoadResource: Send + Sync {
|
#[derive(Clone, DynAny)]
|
||||||
fn load(&self, hash: ResourceHash) -> ResourceFuture;
|
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 {
|
pub fn new_unchecked<T: AsRef<[u8]> + Send + Sync + 'static>(data: T, hash: ResourceHash) -> Self {
|
||||||
fn store(&mut self, data: &[u8]) -> ResourceHash;
|
Self { inner: Arc::new(data), hash }
|
||||||
fn contains(&mut self, hash: &ResourceHash) -> bool;
|
}
|
||||||
fn garbage_collect(&mut self, used: &[ResourceHash]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(transparent)]
|
pub fn hash(&self) -> ResourceHash {
|
||||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, graphene_hash::CacheHash, PartialOrd, Ord, DynAny)]
|
self.hash
|
||||||
#[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 {
|
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 {
|
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 {
|
impl std::fmt::Display for ResourceHash {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_str(&String::from(self))
|
f.write_str(&String::from(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,8 +141,8 @@ pub enum ResourceHashParseError {
|
|||||||
InvalidCharacter { byte: u8, position: usize },
|
InvalidCharacter { byte: u8, position: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ResourceHashParseError {
|
impl std::fmt::Display for ResourceHashParseError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::InvalidLength { found } => write!(f, "resource hash must be 64 hex characters, got {found}"),
|
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}"),
|
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 {
|
impl<'de> serde::de::Visitor<'de> for ResourceHashVisitor {
|
||||||
type Value = ResourceHash;
|
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")
|
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]>;
|
pub type DataSources = Box<[DataSource]>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ std = [
|
|||||||
"serde",
|
"serde",
|
||||||
"dep:core-types",
|
"dep:core-types",
|
||||||
"dep:dyn-any",
|
"dep:dyn-any",
|
||||||
|
"dep:graphene-resource",
|
||||||
"dep:graphene-hash",
|
"dep:graphene-hash",
|
||||||
"dep:raster-types",
|
"dep:raster-types",
|
||||||
"dep:vector-types",
|
"dep:vector-types",
|
||||||
@@ -43,6 +44,7 @@ node-macro = { workspace = true }
|
|||||||
# Local std dependencies
|
# Local std dependencies
|
||||||
dyn-any = { workspace = true, optional = true }
|
dyn-any = { workspace = true, optional = true }
|
||||||
core-types = { workspace = true, optional = true }
|
core-types = { workspace = true, optional = true }
|
||||||
|
graphene-resource = { workspace = true, optional = true }
|
||||||
graphene-hash = { workspace = true, optional = true }
|
graphene-hash = { workspace = true, optional = true }
|
||||||
raster-types = { workspace = true, optional = true }
|
raster-types = { workspace = true, optional = true }
|
||||||
vector-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::context::{Ctx, ExtractFootprint};
|
||||||
use core_types::list::{Item, List};
|
use core_types::list::{Item, List};
|
||||||
use core_types::math::bbox::Bbox;
|
use core_types::math::bbox::Bbox;
|
||||||
use core_types::resource::Resource;
|
|
||||||
use core_types::transform::Transform;
|
use core_types::transform::Transform;
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
use fastnoise_lite;
|
use fastnoise_lite;
|
||||||
use glam::{DAffine2, DVec2, Vec2};
|
use glam::{DAffine2, DVec2, Vec2};
|
||||||
|
use graphene_resource::Resource;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use rand_chacha::ChaCha8Rng;
|
use rand_chacha::ChaCha8Rng;
|
||||||
use raster_types::Image;
|
use raster_types::Image;
|
||||||
|
|||||||
Reference in New Issue
Block a user