Repository navigation
feat(libSceJson2): implement Value::setTypeMismatchHandler and store the element access failure and special float handlers - #6126
Conversation
Progress report (db7176f → 7e4b1b7)📈 System libraries: 89.46% (+0.08%, +3 implemented functions) ✅ 3 implemented
|
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
|
Resident Evil 4 (PPSA07411) on plain So this PR addresses the title's current first stop on AI-assisted: yes |
|
Tested on Linux x86-64 (Release build), with 5dd4c4e merged into main ab9a476:
AI-assisted: yes (Claude Code) |
|
Follow-up run with this PR's
The run never reached the per- AI-assisted: yes |
…the element access failure and special float handlers Value::setTypeMismatchHandler, setElementAccessFailureHandler and setSpecialFloatHandler were stubs that threw NotImplemented. PPSA07411 calls all three while it sets up its documents. The title calls them as members of Value: on its root Value before parsing into it, with the handler and its context, and treats an int result of 0 as success. They now store the handler and context on that Value and on the values it holds, and return 0. A Value keeps its handlers when its content changes (set, clear, operator=, Parser::parse), and Parser::parse gives the values it creates the handlers of the Value it parses into, since the title reads the errors its handlers record after accessing parsed members. A copy does not carry them. A typed getter on a non-null value of another type calls the type mismatch handler with the requested type, the value, null and the context, and returns its result when it has the requested type, else the getter's default. The element access failure and special float handlers are stored but not called: the error code the console passes to the first and the FunctionType it passes to the second are unknown. A failed element access on a value carrying the first throws instead of reaching the null-access callback. Serializing a non-finite real already threw; with the second set it throws naming the unknown FunctionType. The technical debt entry records what is inferred. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Rebased onto current |
5dd4c4e to
7e4b1b7
Compare
|
The handler plumbing reads right, and keeping the two unverified handlers throwing is good. Two small doc points: the debt entries name the title (PPSA07411); could they drop it, as it's in the PR body already? And could the type-mismatch entry note that the third argument is passed as null, which isn't verified against the console? |
What
sce::Json::Value::setTypeMismatchHandler,setElementAccessFailureHandlerandsetSpecialFloatHandlerwereNotImplementedstubs. PPSA07411 calls all three right aftersetNullAccessCallBack, so its boot stopped on the first one.This PR implements the type mismatch handler. The element access failure and special float handlers are stored but not called yet: their use sites throw, because what the console passes them is unknown (details below).
How the title calls them (its
eboot.elfwas read, not run):Value, not static functions. The title calls each one on the rootValueof its document wrapper withthisinrdi, the handler inrsiand the context inrdx. It calls them before it parses into thatValue.Valueargument.getValue,getStringon child values), it reads that error from the root's context. So handlers registered on the root before parsing have to reach the values the parse creates.The PS Vita
sce::Jsonlibrary also declares aValuehandler setter,setNullAccessCallback, as a member that returns int (vitasdk json.h L638).The change (
core/libs/prx/libSceJson2/Export.cpp):(Value* this, handler, context), store the handler and context on thatValueand on the values it holds, and return 0. A null handler clears it.Valuekeeps its handlers when its content changes (set,set(const Value&),clear,operator=,Parser::parse).Parser::parsegives the values it creates the handlers of theValueit parses into. A copy-constructedValue,push_backandObject::operator[]do not carry them.getBoolean,getInteger,getUInteger,getReal,getString,getArray,getObject) on a non-null value of another type calls the handler with(requested type, the value, null, context). It returns the handler's value if that value has the requested type, else the getter's default, as the null-access path does. A null-typed value still goes to the null-access callback, and a value without the handler behaves as before. The null secondValueand the order of the twoValuearguments are inferred, not known.operator[]orgetValueon a value carrying this handler throws instead of calling it with an invented code. The title registers this handler on its root before parsing, so every failed lookup in its parsed documents now throws; if it looks up optional keys, its boot stops there with that error. Without the handler, the access still reaches the null-access callback.FunctionTypevalues and the meaning of thebool*output are unknown, and the title's handler returns a different replacement for each of its two types, so picking a numbering would silently change the output. Serializing a non-finite real already threw without the handler. With it, the only change is the exception message, which names the unknownFunctionType; the setter has no other observable effect.docs/dev/debt/libSceJson2.mdrecords what is inferred and what is unknown: how the console finds an accessed value's handler, the secondValueargument and the argument order, the error code and theFunctionTypevalues. The three members are removed from the PPSA07411 list of declarations with unknown signatures indocs/dev/debt/libSceSsl.md, which now names onlyoperator bool.operator boolis a separate topic and is untouched.Not in this PR:
Value::setNullAccessCallBack. The title calls it the same way as the three handlers (a member,thisfirst), but onmainit is a static(callback, context)function, so it stores the title'sValuepointer as the global null-access callback and the handler as its context. Onmainthe title stops with a cleanNotImplementedatsetTypeMismatchHandler. With this PR it gets past that stop, and its next null access (a typed getter on a JSONnull, or a failed lookup or type mismatch on a value that does not carry the handlers) calls into data and faults instead of throwing. That needs its own fix (setNullAccessCallBackas a member that stores the callback perValue), so this PR alone does not unblock the title.Tested
Windows Server 2025 (10.0.26100), WinLibs MinGW-w64 GCC 15.2.0, Ninja, Release,
BUILD_TESTING=ON, onmaineea428c. No title run.core/libs/tests/GuestJson.cpp(guest_json) gains three cases:ValueTypeMismatchHandler: with the handler set on the root before parsing,getIntegeron a parsed string member returns the handler's integer, and the handler receives(TypeInteger, &member, null, &context).getBooleangets the getter's default when the handler returns another type. A matching getter does not call it. Mismatches on the root and on a nested array element call it with that value. A null member goes to the null-access path. A document parsed without the handler gets it when it is set afterwards. Afterroot = other,root.set(const Value&), andValue::clearfollowed byset(const char*), a mismatch on the root still calls the handler; the assigned-fromValuedoes not get it, and a copy-constructedValuedoes not carry it. Clearing the handler restores the default.ValueElementAccessFailureHandler: successful accesses work. A missing key throughoperator[]andgetValue(String), an index into an object and an out-of-rangegetValue(size_t)on a child all throw "unverified", and the handler is not called. After clearing, they return null values.ValueSpecialFloatHandler: serializing NaN and infinity with the handler set throws "unverified" without calling it. The handler survivesset(double), and a finite value serializes as2.5.Results:
main'sExport.cpp:guest_jsonaborts (0xc0000409) with..._ZN3sce4Json5Value22setTypeMismatchHandler... not implemented. With each of the other two cases moved first, it aborts withsetElementAccessFailureHandler ... not implementedandsetSpecialFloatHandler ... not implemented.copy.handlers = destination.handlers;fromAssignNode(handlers lost onoperator=andset(const Value&)) fails at the newoperator=assertion. Removing the handler restore fromClearfails as well.ctest -R guest_json --repeat until-fail:3passes (0.09 to 0.24 s per run). guest_json is the library's only test.tools/check_conventions.pyfrommain,--base upstream/main --head HEADwith this title and body: passed.git merge-tree: this branch merges cleanly with feat(libSceJson2): implement sce::Json::String methods and npos #5439, which also changes the Json2Export.cppandGuestJson.cpp. It conflicts with feat(libSceSsl): record connection verify options, minimum version and ALPN #5911 and docs: fix Pages workflow link and separate library technical debt #6039 only on the PPSA07411 line ofdocs/dev/debt/libSceSsl.md, which all three rewrite. Whichever merges later resolves that one line.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)setTypeMismatchHandler; its next stop issetNullAccessCallBack(see What). No Game bring-up discussion yet🤖 Generated with Claude Code