1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/// methods to create HTML Elements as well as their types
pub mod create;
pub mod dom_events;
pub mod element;
mod enclose;
pub mod entity;
/// simple way to fire and respond to arbitrarily-typed events
pub mod events;
/// Parent and Child relations
pub mod hierarchy;
pub mod prelude;
pub mod query;
mod racy_cell;
/// resources are globally-accessible components
pub mod resource;
pub mod signals_ext;
mod storage;
mod style_storage;
pub mod web_str;
mod world;

pub use web_sys;
use crate::prelude::*;
#[doc(hidden)] pub use discard;
pub use element::{AsElement, Element};
pub use entity::AsEntity;
pub use futures_signals as signals;
pub use hobo_css as css;
use owning_ref::{OwningRef, OwningRefMut};
#[doc(hidden)] pub use paste;
pub use prelude::{Children, Parent};
use std::{
	any::TypeId,
	cell::{Ref, RefMut},
};
use style_storage::{StyleStorage, STYLE_STORAGE};
use sugars::hash;
#[doc(hidden)] pub use world::World;
pub use owning_ref;

// NOTES:
// queries to be able to find entities with/by components in children/parent/ancestor/family - done
// * optionaly specify depth?
// resources stay, resources could be useful for caching/memoization/etc
// add a name component that sets data-name or smth
// * should be possible to find by name for those cases where you cba to set up a proper relationship
// could use an attribute macro over intostyle expressions to give them names and use names rather than hashes
// organise uses, itnernal prelude uses could be pub(crate)
// test shit ffs
// could? remove all *_mut elements and specify whether you want mutable or immutable component with the same trick as in Query

#[cfg(debug_assertions)]
pub mod backtrace {
	use super::*;
	use std::{
		collections::{HashMap, BTreeMap},
		cell::RefCell,
		panic::Location,
	};
	use once_cell::sync::Lazy;
	use shrinkwraprs::Shrinkwrap;

	pub static STORAGE_MAP: Lazy<BacktraceStorage> = Lazy::new(Default::default);

	#[repr(transparent)]
	#[derive(Debug, Default)]
	pub struct BacktraceStorage<'a>(pub RefCell<HashMap<TypeId, LocationMap<'a>>>);

	unsafe impl Send for BacktraceStorage<'_> {}
	unsafe impl Sync for BacktraceStorage<'_> {}

	#[repr(transparent)]
	#[derive(Debug, Default, Shrinkwrap)]
	#[shrinkwrap(mutable)]
	pub struct LocationMap<'a>(pub BTreeMap<Location<'a>, bool>);

	impl<'a> std::fmt::Display for LocationMap<'a> {
		fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
			for (location, mutable) in self.iter().rev() {
				// pretty offset
				writeln!(f, "{:>5} {}", if *mutable { "(mut)" } else { "" }, location)?;
			};
			Ok(())
		}
	}
}

// this is not necessary, but it makes it convenient to further remap to some OwningRef or whatever
pub type StorageRef<'a, Component> = OwningRef<Ref<'a, Box<dyn storage::DynStorage>>, Storage<Component>>;
pub type StorageRefMut<'a, Component> = OwningRefMut<RefMut<'a, Box<dyn storage::DynStorage>>, Storage<Component>>;

/// Register a browser window to also receive styles, automatically called for the global `window` object with the name "default"
pub fn register_window(window: &web_sys::Window, window_name: String) {
	let style_storage = unsafe { &mut *STYLE_STORAGE.get() as &mut StyleStorage };
	style_storage.register_window(window, window_name);
}

/// Removes a window from the style storage
pub fn unregister_window(window_name: &str) {
	let style_storage = unsafe { &mut *STYLE_STORAGE.get() as &mut StyleStorage };
	style_storage.unregister_window(window_name);
}

#[doc(hidden)]
#[extend::ext(pub, name = MarkClassString)]
impl<T: 'static> T {
	fn mark_class_string() -> String {
		format!("t-{:x}", hash!(TypeId::of::<Self>()))
	}
}

/// Find all entities matching a query
pub fn find<Q: query::Query>() -> Vec<Q::Fetch> {
	let mut entities = None;
	Q::filter(&WORLD, &mut entities);
	entities.unwrap_or_default().into_iter().map(|entity| Q::fetch(&WORLD, entity)).collect::<Vec<_>>()
}

/// Find one entity matching a query if there is one
pub fn try_find_one<Q: query::Query>() -> Option<Q::Fetch> {
	let mut entities = None;
	Q::filter(&WORLD, &mut entities);
	entities.unwrap_or_default().into_iter().next().map(|entity| Q::fetch(&WORLD, entity))
}

/// Find one entity matching a query, panic otherwise
pub fn find_one<Q: query::Query>() -> Q::Fetch { try_find_one::<Q>().unwrap() }

// #[doc(hidden)]
// pub fn world() -> world::WorldMut {
//     World::mark_borrow_mut();
//     let world = unsafe { &mut *WORLD.get() as &mut World };
//     world::WorldMut(world)
// }