# Todos: Written Out Again $table::name should be static, not const can probably remove $table::swap, $table::clear we need predicates generate_events: New, view_events: &See, filter_events: &mut See, take_events: Take, Requiring a trait for properties to impl is sucky. I think we should just allow any ol' Any+Send+Sync to be inserted. Ah, the solution is simple. Call universe.install::(t). This inserts T, and registers extractors for &T and &mut T. rework kernel running so that it's less awful to step through in GDB. We ideally have, like, just the 1 stack frame. - We might want to do some defer nonsense to get rid of that *awful* std::panic::catch. - Or we could just abort!? - ... Well, we want real stacktraces at least. - But maybe we don't! Actually release-mode stacktraces are useless, even with trimming. # Documentation Explain that you can't extract owned things. Explain the universe methods implemented in each module. Document table!'s output Document context!'s output Universe item docs are dumb crate docs: s/map/run # Polish we can remove universe.kmap() now that we have eval(). the firewall in table! can probably go away now that we have the 'mod types' crate::macro_prelude -> crate::tables::prelude remove abs path requirement on tables column::set_data() should be unsafe, and its fields should be private, and it should have an unsafe constructor. But OTOH, there's also Serde, sooooo.... Oh! But our columns are usually wrapped in WriteColumn or w/e, so maybe that could make it nicer... Add "ImmediateEdit" so you can say `Immediate`. It would allow editing a column without there being any question of logging. This would maybe allow some sweet SIMD optimizations or something. It would have to assert, during Extract, that there were no trackers. impl Extract for T where T: Property + Copy Delete 'kmap'; eval's better. s/remove/delete. The distinction isn't helpful. s/is_tracked/is_tracking. Or just 'tracked' or 'tracking'? Running a Kernel is far too much work for the computer. # Consistency/Ordering Issue We acquire a bunch of locks. We do stuff to 'em. Some events need to be submitted to maintain data consistency - So NOBODY ELSE can be acquiring locks. Suppose we've got this event we need to submit. It's gonna modify some other column we don't have a lock on. And it's gonna modify a column we DO have a lock on Nobody should be allowed to acquire those columns! * We need to hold the lock on the edit column until consistency has been propagated. * Doing consistency can result in ARBITRARY COLUMN ACCESS!? * How 'bout this. ThreadId. Only the current thread can acquire locks. - They can release locks if they like. What if the locks required by every following event handler were reserved before the locks held for the executing kernel were released? It would be nice to have a way to indicate a bi-directional dependency. - Deleting the foreign row deletes the local row. - We might want the reverse to happen also. It would make sense for any direct RowId to cause removal if the foreign row were removed. We could also have "Owns", which would delete the foreign row if the local row is deleted? # Uhm We should make it so that you have the option of that, when you call 'remove' on something, if it's got linkage, it also removes the foreign table? Maybe you should just delete from the foreign table instead? Mark Column::push as unsafe. Isn't kernel.rs/fn prepare_buffer supposed to, y'know, not spin infinitely while waiting!? # Yeah We need a 'kernel mask' feature. A kernel can provide a HashMap. The items would be (Plane, PreviewOf), but the value of PreviewOf would be just Plane. This takes advantage of the fact that HashMap> can have a mismatch between the key and the type_id of the value. It's just a single layer of indirection. Also we might just use a flat Vec<(TypeId, TypeId)>, instead of HashMap. - But the idea is that we want to be able to run Kernels without having to know that a mask's been set. # ... Yeah! So we have a universe, but we might want to create a universe that's the same, but like "oh plane is a different dimension". What we do is we have a ThreadLocal. Variant can be a TypeId or a UUID. When we look up some T:TypeId, we first look for `T ^ variant` for each variant mask. Maybe Variant is an AtomicU64. Have `known_variants: Vec`. Check for hash collisions. Maybe our HashMap should be HashMap; and impl From for Variant. Likely good idea, hmm? :D HashMap>; gives a description of every variant. We say "key variant" and "mask variant" Variant::new_dynamic() uses RNG to create one w/o a TypeId; useful for eg multiple dimensions. Universe::push_mask(Variant)? Vec or singleton, hmm? # Stuff It'd be cool to have Edit::into_write(self) and Write::into_edit(self). Or maybe: Edit::then_push(self, Vec) Edit::then_remove(self, Vec) Maybe the idea is that there's a chain of change sets. Vec You queue up some changes... Maybe it's a "BufferedMut". You say "I'm going to edit these rows", and then "I'm going to push these rows", and then "I'm going to remove these rows", and any of these can happen in any order, and the Universe does its reactions between each step. Ooh! Maybe it's just like an external thingie. # Things Facts (Events). You can have Emit (or Log ?) trait Extract: fn install_on(&mut Universe) {} This allows you to take `Log` as a kernel arg. if you want uh Iterator-combinator style kernels, you'd probably need a separate Kernel type... Like what if you took some kind of Iterator-combinator as a param? It'd suck, probably. Maybe the iterator is built dynamically sorta, like you say items.select_where(items::Id, bodies::Inv).each(|_| {})... Better: You say Kernel::iter( items::select_where_in(items::Id, bodies::Inv), | item_type: items::type::ItemType, item_id: items::Id, bod: bodies::Id, players: players::Edit, | { // ... }, ); Insufficiently better! items::select_where_in(items::Id, bodies::Inv) .map(| item_type: items::type::ItemType, item_id: items::Id, bod: bodies::Id, players: players::Edit, | { // ... }) items::read::Id::select_from::(| item_type: items::type::ItemType, item_id: items::Id, bod: bodies::Id, players: players::Edit, | { // ... }) Kernel Variants The 'edit maybe logs' thing is sad. We could have a mechanism where you give a bunch of kernels in order of efficiency. There's a PredicateCell-thingie that says which one is the best to use. It calculates it by going through each of the arguments; `Extract` gets a `is_usable` thingie -- or something that just allows figuring out if a column has a tracker. PredicateCell value calculated from a kernel. Looks at the utilized types, and re-evaluates the cell whenever an input changes. ReducePredicateCell cell has a default value. Has two mandatory arguments, 'previous value' and 'new rows'. (T: Default; have to calc from scratch if a col is edited. Or just crash!) we could say 'we need to watch these particular rows'. Like we have a Selection, say. Very messy! Far too ugly IMO. row edited? predicate(Default(), old_value) != predicate(Default(), new_value) --> recalc all wait, a join wouldn't be so bad. I may have gotten past wanting PredicateCells by virtue of TagDB? # documentation [package.metadata.docs.rs] features = [ "feature1", "feature2" ] all-features = true no-default-features = true default-target = "x86_64-unknown-linux-gnu" rustc-args = [ "--example-rustc-arg" ] rustdoc-args = [ "--example-rustdoc-arg" ]