Add package-level datasource declarations#361
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces package-level datasource declarations so package.lua can declare datasource provider metadata (name/type/params) and have it surface on Project.DataSources, alongside updates to sample packages and a regression test. It also updates Lua↔C property hydration to better handle struct/object tables used by package metadata.
Changes:
- Add
Project.DataSourcesas a new schema surface (with a sealedDataSourcestruct) in the filesystem module. - Declare XML datasources in
samples/Example/package.luaandsamples/Adventure/package.lua. - Extend Lua property hydration/serialization to handle struct/object tables and array properties; add a focused layout test for package datasource declarations.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/test_layout.lua | Adds a regression test asserting package-level datasource declarations are present for the Example sample. |
| source/filesystem/filesystem.cgen | Adds the DataSource struct and the Project.DataSources array property to the filesystem schema. |
| source/core/property/property_lua.c | Updates Lua property read/write logic to better handle struct/object tables and array properties. |
| samples/Example/package.lua | Adds an Example datasource declaration (ApplicationData). |
| samples/Adventure/package.lua | Adds Adventure datasource declarations (Games, Tabs). |
Comments suppressed due to low confidence (1)
source/core/property/property_lua.c:105
- Array property deserialization iterates the Lua table with lua_next but writes elements sequentially via an incrementing index. If the table is sparse (e.g. { [3] = ... }) or contains numeric keys outside 1..lua_rawlen, this will write past the calloc() buffer (or into a 0-length allocation), causing memory corruption/crashes. Use the numeric key to compute the destination index and validate it is within 1..numitems before writing.
while (lua_next(L, idx) != 0) {
if (lua_type(L, -2) != LUA_TNUMBER) {
free(tmp);
luaL_error(L, "Expected numeric keys in array table for property %s", prop->Name);
}
| if (prop->IsArray) { | ||
| void *items = valueptr ? *(void *const*)valueptr : NULL; | ||
| int count = valueptr ? ((int const*)valueptr)[sizeof(void*)/sizeof(int)] : 0; |
- Add provider registry: FS_RegisterDataSourceProvider, FS_RegisterDataSource, FS_ResolveDataSource - Register XML provider as first concrete fetch handler - Rewrite DataContextSource to resolve names through registry with file-path fallback - Register package DataSources into global registry at bundle load - Add tests for provider-based DataContextSource resolution
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
source/core/property/property_lua.c:105
- Array-property decoding allocates storage based on lua_rawlen() but iterates elements via lua_next() without enforcing contiguous 1-based keys. Sparse arrays (e.g. { [1]=..., [3]=... }) will overflow the allocated buffer as i increments past numitems. Add a key check to require contiguous 1..N numeric indices (or switch to a lua_rawgeti loop).
while (lua_next(L, idx) != 0) {
if (lua_type(L, -2) != LUA_TNUMBER) {
free(tmp);
luaL_error(L, "Expected numeric keys in array table for property %s", prop->Name);
}
| struct Object *dataObj = FS_ResolveDataSource(ds_name, NULL); | ||
| if (!dataObj) { | ||
| // Fallback: treat as a direct file path (backward compatibility) | ||
| dataObj = FS_LoadObject(value); | ||
| } |
| void | ||
| FS_RegisterDataSource(const char *name, const char *type, const char *params) | ||
| { | ||
| if (_ds_entry_count >= MAX_DATASOURCE_ENTRIES) { | ||
| Con_Error("No space to register datasource '%s'", name); | ||
| return; | ||
| } | ||
| struct ds_entry *e = &_ds_entries[_ds_entry_count++]; | ||
| strncpy(e->name, name, sizeof(e->name) - 1); | ||
| strncpy(e->type, type, sizeof(e->type) - 1); | ||
| strncpy(e->params, params, sizeof(e->params) - 1); | ||
| } |
- Add SelectedItem (DataObject*) property to ItemsControl in UIKit.cgen - ListBox sets SelectedItem to clicked item's DataContext on selection - OBJ_FindPropertyByPath now navigates through object-typed properties in multi-segment paths (e.g. SelectedItem/Title) - 9 tests covering all selection paths and master-detail data navigation
|
@copilot Fix webgl build, why is it broken? |
Co-authored-by: corepunch <83646194+corepunch@users.noreply.github.com>
- Add FS_RegisterDataProvider with save/revert callbacks - Add FS_ClearProjectDataSources for per-project cleanup - Add session cache for FS_ResolveDataSource - Add FS_MarkDataSourceDirty, FS_SaveDataSource, FS_RevertDataSource - Add FS_ClearAllDataSources to FS_Shutdown - Add unloadProject Lua API for explicit project unload - Add Screen.SaveChanges message handler - Update XML provider with save/revert implementations - Add lifecycle tests: cleanup, reload, repeated load/unload - Update existing datasource tests to use unloadProject
…warnings - Update Example/Application.xml: DataContextSource and ItemsSource use datasource names instead of direct file paths (e.g. 'ApplicationData:Metrics') - Update Adventure/Adventures.xml: ItemsSource='Tabs' instead of 'Adventure/Data/Tabs' - Update Adventure/GameList.xml: ItemsSource='Games:Catalog' instead of 'Adventure/Data/Games:Catalog' - Add provider registry lookup to property_lua.c kDataTypeObject handler - Add Con_Warning when file-path fallback is taken in fs_xml.c and property_lua.c - Update test_layout.lua to match new name-based syntax
- Add Schema field to DataSource struct in filesystem.cgen - Add ds_schema, ds_entity, ds_column structures for column metadata - Add _ParseSchema to load schema XML files (libxml2-based) - Schema is cached in ds_session on first resolve - FS_GetDataSourceSchema and FS_FindSchemaColumn for querying metadata - Schema path is appended to params as &Schema= for provider transport - Example project: add ApplicationData.Schema.xml with Signals/Metrics entities - Example package.lua: reference schema in DataSource declaration - Memory cleanup: free schemas on session/registry teardown - Tests: schema file load, schema field in package.lua, schema in params
…taSourceLibrary - Replace flat DataSources struct array with DataSourceLibrary using XmlDataSource objects in package.lua samples - Add Object.Start handler for XmlDataSource to load XML source - Fall back to registered class constructors in OBJ_GetProperty for declarative environments - Treat array-part userdata entries as children in create_object_from_table - Update FS_LoadBundle to iterate DataSourceLibrary children instead of DataSources array
Resolve datasource classes explicitly with require 'orca.filesystem.XmlDataSource' instead of a global class-name fallback in OBJ_GetProperty. - revert the OBJ_GetProperty class-registry fallback - give package.lua a proxy _ENV: reads fall back to _G (so require works), writes forward to the project object - add an orca.<module>.<Class> package.searchers entry (fs_findclass) - port Example and Adventure samples to require the class
|
@copilot See if still makes sense to address the review comments, if it is, provide fixes |
Co-authored-by: corepunch <83646194+corepunch@users.noreply.github.com>
Still-valid review comments were worth fixing, and I addressed them in |
…inline Remove attach_children flag and separate attach_object_children_from_table function — child attachment is now unconditional in the single table pass.
- add XML aliases: group/object, string/int/float/bool - accept lowercase attribute aliases in XML loader - map text node content to Value when value attr is omitted - migrate Adventure datasource XML to compact style - keep datasource registration deterministic at project load
- XmlDataSource.Start eagerly loads XML into owned DataObject tree - FS_ResolveDataSource checks for owned DataObject before session fallback - ListBox.Start refactored to compact C idioms - Added Data property to DataSource class - Documented compact C coding style in AGENTS.md
- Introduce DataContext as base for both DataSource and DataObject - Move Data property from DataSource up to DataContext - Add core_GetDataContextData helper to resolve root DataObject - Update binding engine to go through DataContext chain - Set XmlDataSource (not DataObject) as Node.DataContext - Add FS_FindDataSource for non-resolving lookups - Update DataContextSource attr to retain DataSource reference
- Replace DataContext.Data property with DataContext.GetData message - Remove core_GetDataContextData helper; use _SendMessage instead - DataSource stores its DataObject in a field, handles GetData - DataObject handles GetData via OBJ_FindByPath through children - Binding engine splits path at '/' and resolves via GetData - ListBox: pass pointer arg to PROP_SetValue for string property - Add tests for default template, data wiring, nested paths
|
@copilot Webgl fails, see what's wrong and fix |
Co-authored-by: corepunch <83646194+corepunch@users.noreply.github.com>
Fixed in |
Summary
This PR implements the datasource provider gateway pattern —
package.luadeclares named data sources, views bind to them by name, and providers handle fetch/save/revert behind a message-driven contract.Architecture
How it's done
Provider registry (
filesystem.c):FS_RegisterDataProvideraccepts fetch + save + revert callbacks.FS_RegisterProjectDataSourcestores entries with project ownership.FS_ResolveDataSourcechecks session cache first, then walks entries → finds matching provider type → calls fetch → caches in session.FS_ClearProjectDataSources(removes entries + invalidates orphaned sessions). Full reset viaFS_ClearAllDataSources.Lifecycle (
w_filesystem.c):filesystem.init→FS_LoadBundle→ registers each DataSource viaFS_RegisterProjectDataSource, passing the optionalSchemafield appended to params as&Schema=....filesystem.unloadProject→FS_ClearProjectDataSources+OBJ_Clear+OBJ_RemoveFromParent.Project.Object.Releasehandler fires on object destruction as a safety net.Master-detail (
UIKit.cgen,ListBox.c,object_hierarchy.c):ItemsControl.SelectedItem(DataObject*) added to the .cgen, auto-generated as a struct field with property ID/short-ID registration.ListBoxsetsSelectedItem = itemNode->DataContextinListBox_SetSelected(andListBox_SyncToSelectedValuefor binding-driven changes).OBJ_FindPropertyByPathextended: when a path segment isn't a child object, it tries finding an object-typed property, reads the component pointer, callsCMP_GetObject, and continues resolution on the pointed-to object. This enables paths likeSelectedItem/Title.Data mutations (
filesystem.c,fs_local.h):ds_providerstruct extended withsaveandrevertfunction pointers.FS_SaveDataSource(name): finds session → calls provider'ssave(root, params)→ marks clean on success.FS_RevertDataSource(name): calls provider'srevert(root, params)→ marks clean.FS_MarkDataSourceDirty(name): sets session dirty flag for tracked changes._xml_ds_save: serializes DataObject tree to XML viaFS_SerializeObjectToXmlStringand writes to the file path from params._xml_ds_revert: invalidates session cache (nextResolveDataSourcereloads).Screen.SaveChangesmessage registered as a hook point for UI-level save triggers.Deprecation + sample migration (
fs_xml.c,property_lua.c):DataContextSourcehandler: after provider lookup fails, emitsCon_Warningbefore file-path fallback.property_lua.ckDataTypeObjecthandler: triesFS_ResolveDataSourcebeforeFS_LoadObject, with deprecation warning on fallback.ItemsSource="ApplicationData:Metrics"instead ofExample/Data/ApplicationData:Metrics.Optional schema (
filesystem.c,filesystem.cgen):DataSourcestruct gains aSchema(string) field.ds_schema/ds_entity/ds_columnstructs hold parsed column metadata._ParseSchemauses libxml2 to read<Schema>→<Entity>→<Column>hierarchy.FS_GetDataSourceSchemaandFS_FindSchemaColumnprovide runtime metadata access.Test strategy
test_layout.luatest_pagehost_listbox.luaFiles changed
source/filesystem/filesystem.cgenDataSourcesealed struct (+ Schema field),Project.DataSourcesarraysource/filesystem/filesystem.csource/filesystem/fs_local.hsource/filesystem/fs_xml.csource/filesystem/w_filesystem.csource/core/property/property_lua.csource/core/object/object_hierarchy.cOBJ_FindPropertyByPathnavigates through object propertiesplugins/UIKit/UIKit.cgenItemsControl.SelectedItem,Screen.SaveChangesmessageplugins/UIKit/ListBox.cplugins/UIKit/Screen.csamples/Example/package.luasamples/Example/Screens/Application.xmlsamples/Example/Data/ApplicationData.Schema.xmlsamples/Adventure/Screens/Adventures.xmlsamples/Adventure/Pages/GameList.xmltests/test_layout.luatests/test_pagehost_listbox.luaValidation
make test-headless— all tests pass, zero regressions