Repository navigation
Write each element with a plain XMLWriter - #86
Conversation
Every element goes through Writer::write, which wraps whatever its generator throws in a veewee RuntimeException and turns libxml issues into one. Callers see that wrapping, nested once per element and unwrapped by the envelope only when an EncodingException sits right under it. These tests fix that behaviour before the writer changes.
XsdTypeXmlElementWriter runs once per encoded element and opened a veewee/xml Writer every time. That costs a configure() pipeline, a Psl Result with closures and an IssueCollection from disallow_issues, and a guard call per yielded value, even when nothing goes wrong. It now opens XMLWriter::toMemory() itself and checks for false inline. It keeps the same libxml error handling as disallow_issues and builds the IssueCollection only when there is a failure or a libxml error, so callers get the same exceptions as before.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
The plain XMLWriter loop with the libxml error handling lived inside XsdTypeXmlElementWriter. It moves into its own writer so the envelope and the fault encoders can use it too, with the same exceptions as veewee/xml Writer::write and disallow_issues. The exception and libxml tests now pin that behaviour on InMemoryXmlWriter, and XsdTypeXmlElementWriter keeps a thin test.
The envelope and both fault encoders built their XML through veewee/xml Writer::inMemory with the same error contract InMemoryXmlWriter keeps, so they now share it with the element writer. New tests pin the exact bytes of an envelope and of both faults; they passed against the previous writer as well. The envelope still unwraps an EncodingException from the RuntimeException exactly as before.
Summary
XsdTypeXmlElementWriterruns once for every encoded element and opened a newWriter::inMemory()each time. Most of that cost is in the veewee/xml wrapper rather than in XMLWriter.configure()folds an empty pipeline throughIter\reduce,disallow_issuesbuilds a PslResult, two closures and anIssueCollectioneven when nothing went wrong, andwrite()calls a guard function for every yielded value. The 3MB dense encode goes through this about 157k times per call.This PR adds
Soap\Encoding\Xml\Writer\InMemoryXmlWriter, an in-memory XML writer for this package. It takes acallable(XMLWriter): Generator<bool>, opens a freshXMLWriter::toMemory()per call, runs the builder with an inlinefalsecheck and returnsoutputMemory(). It holds no state between calls.XsdTypeXmlElementWriternow delegates to it, and so doSoapEnvelopeWriter,Soap11FaultEncoderandSoap12FaultEncoder, which were the other places building XML throughWriter::inMemory(). The builders and theXmlEncodercontract stay as they are.Same exceptions
Callers can see the old wrapping. Anything thrown inside a builder comes out as a veewee
RuntimeExceptionwith the original as previous, wrapped once more for each element level it passes through. Libxml errors raised during the write fail it as well.SoapEnvelopeWriteronly unwraps one level, so an encoder that relies on this would notice a change.InMemoryXmlWriterreplicatesWriter::writewithdisallow_issueswithout the overhead: the samelibxml_use_internal_errorsandlibxml_clear_errorssequence, the sameRuntimeExceptionfactories and messages, and anIssueCollectionthat is only built when there is a failure or a libxml error.The first commit adds tests for this that pass on main before the writer changes. They now pin that behaviour on
InMemoryXmlWriterdirectly: a throw inside the builder, afalsewrite, an invalid element name, libxml issues with and without a throw, nested writes, and the libxml error state afterwards.XsdTypeXmlElementWriterkeeps a thin test,SoapEnvelopeWriterTeststill covers an element failure seen from the envelope, and the envelope and both fault encoders have a test that pins their exact output bytes, which passed against the old writer too. The encoded requests and decoded results of the 3MB workloads have the same sha1 before and after.Speed
Median of 3 interleaved rounds on the same machine, with ext-soap as the noise reference.
These numbers were measured before the writer moved into
InMemoryXmlWriter. A 3MB encode round after the move is within noise of them.Decode does not go through this writer and stays within 2%.
Summary by CodeRabbit