omextra 0.0.0.dev503__tar.gz → 0.0.0.dev505__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. {omextra-0.0.0.dev503/omextra.egg-info → omextra-0.0.0.dev505}/PKG-INFO +2 -2
  2. omextra-0.0.0.dev505/omextra/io/buffers/DESIGN.md +253 -0
  3. omextra-0.0.0.dev505/omextra/io/buffers/adapters.py +294 -0
  4. omextra-0.0.0.dev505/omextra/io/buffers/all.py +63 -0
  5. omextra-0.0.0.dev505/omextra/io/buffers/errors.py +54 -0
  6. omextra-0.0.0.dev505/omextra/io/buffers/framing.py +187 -0
  7. omextra-0.0.0.dev505/omextra/io/buffers/linear.py +202 -0
  8. omextra-0.0.0.dev505/omextra/io/buffers/reading.py +149 -0
  9. omextra-0.0.0.dev505/omextra/io/buffers/scanning.py +110 -0
  10. omextra-0.0.0.dev505/omextra/io/buffers/segmented.py +637 -0
  11. omextra-0.0.0.dev505/omextra/io/buffers/types.py +263 -0
  12. omextra-0.0.0.dev505/omextra/io/buffers/utils.py +76 -0
  13. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/_dataclasses.py +8 -8
  14. omextra-0.0.0.dev505/omextra/text/antlr/cli/__init__.py +0 -0
  15. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505/omextra.egg-info}/PKG-INFO +2 -2
  16. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra.egg-info/SOURCES.txt +12 -0
  17. omextra-0.0.0.dev505/omextra.egg-info/requires.txt +1 -0
  18. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/pyproject.toml +3 -2
  19. omextra-0.0.0.dev503/omextra.egg-info/requires.txt +0 -1
  20. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/LICENSE +0 -0
  21. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/MANIFEST.in +0 -0
  22. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/README.md +0 -0
  23. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/.omlish-manifests.json +0 -0
  24. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/README.md +0 -0
  25. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/__about__.py +0 -0
  26. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/__init__.py +0 -0
  27. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/asyncs/__init__.py +0 -0
  28. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/asyncs/bluelet/LICENSE +0 -0
  29. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/asyncs/bluelet/__init__.py +0 -0
  30. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/asyncs/bluelet/all.py +0 -0
  31. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/asyncs/bluelet/api.py +0 -0
  32. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/asyncs/bluelet/core.py +0 -0
  33. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/asyncs/bluelet/events.py +0 -0
  34. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/asyncs/bluelet/files.py +0 -0
  35. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/asyncs/bluelet/runner.py +0 -0
  36. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/asyncs/bluelet/sockets.py +0 -0
  37. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/asyncs/bridge.py +0 -0
  38. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/collections/__init__.py +0 -0
  39. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/collections/hamt/LICENSE +0 -0
  40. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/collections/hamt/__init__.py +0 -0
  41. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/collections/hamt/_hamt.c +0 -0
  42. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/defs.py +0 -0
  43. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/dynamic.py +0 -0
  44. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/__init__.py +0 -0
  45. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/goyaml/LICENSE +0 -0
  46. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/goyaml/__init__.py +0 -0
  47. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/goyaml/ast.py +0 -0
  48. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/goyaml/errors.py +0 -0
  49. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/goyaml/parsing.py +0 -0
  50. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/goyaml/scanning.py +0 -0
  51. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/goyaml/tokens.py +0 -0
  52. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json/Json.g4 +0 -0
  53. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json/__init__.py +0 -0
  54. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json/_antlr/JsonLexer.py +0 -0
  55. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json/_antlr/JsonListener.py +0 -0
  56. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json/_antlr/JsonParser.py +0 -0
  57. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json/_antlr/JsonVisitor.py +0 -0
  58. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json/_antlr/__init__.py +0 -0
  59. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json5/Json5.g4 +0 -0
  60. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json5/__init__.py +0 -0
  61. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json5/_antlr/Json5Lexer.py +0 -0
  62. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json5/_antlr/Json5Listener.py +0 -0
  63. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json5/_antlr/Json5Parser.py +0 -0
  64. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json5/_antlr/Json5Visitor.py +0 -0
  65. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json5/_antlr/__init__.py +0 -0
  66. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/formats/json5/parsing.py +0 -0
  67. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/io/__init__.py +0 -0
  68. {omextra-0.0.0.dev503/omextra/specs → omextra-0.0.0.dev505/omextra/io/buffers}/__init__.py +0 -0
  69. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/io/trampoline.py +0 -0
  70. {omextra-0.0.0.dev503/omextra/specs/proto → omextra-0.0.0.dev505/omextra/specs}/__init__.py +0 -0
  71. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/specs/proto/Protobuf3.g4 +0 -0
  72. {omextra-0.0.0.dev503/omextra/specs/proto/_antlr → omextra-0.0.0.dev505/omextra/specs/proto}/__init__.py +0 -0
  73. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/specs/proto/_antlr/Protobuf3Lexer.py +0 -0
  74. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/specs/proto/_antlr/Protobuf3Listener.py +0 -0
  75. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/specs/proto/_antlr/Protobuf3Parser.py +0 -0
  76. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/specs/proto/_antlr/Protobuf3Visitor.py +0 -0
  77. {omextra-0.0.0.dev503/omextra/sql → omextra-0.0.0.dev505/omextra/specs/proto/_antlr}/__init__.py +0 -0
  78. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/specs/proto/nodes.py +0 -0
  79. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/specs/proto/parsing.py +0 -0
  80. {omextra-0.0.0.dev503/omextra/sql/parsing → omextra-0.0.0.dev505/omextra/sql}/__init__.py +0 -0
  81. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/sql/parsing/Minisql.g4 +0 -0
  82. {omextra-0.0.0.dev503/omextra/sql/parsing/_antlr → omextra-0.0.0.dev505/omextra/sql/parsing}/__init__.py +0 -0
  83. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/sql/parsing/_antlr/MinisqlLexer.py +0 -0
  84. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/sql/parsing/_antlr/MinisqlListener.py +0 -0
  85. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/sql/parsing/_antlr/MinisqlParser.py +0 -0
  86. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/sql/parsing/_antlr/MinisqlVisitor.py +0 -0
  87. {omextra-0.0.0.dev503/omextra/text → omextra-0.0.0.dev505/omextra/sql/parsing/_antlr}/__init__.py +0 -0
  88. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/sql/parsing/parsing.py +0 -0
  89. {omextra-0.0.0.dev503/omextra/text/abnf/docs → omextra-0.0.0.dev505/omextra/text}/__init__.py +0 -0
  90. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/LICENSE +0 -0
  91. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/__init__.py +0 -0
  92. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/base.py +0 -0
  93. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/core.py +0 -0
  94. {omextra-0.0.0.dev503/omextra/text/antlr/cli → omextra-0.0.0.dev505/omextra/text/abnf/docs}/__init__.py +0 -0
  95. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/docs/rfc5234.txt +0 -0
  96. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/docs/rfc7405.txt +0 -0
  97. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/errors.py +0 -0
  98. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/grammars.py +0 -0
  99. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/internal.py +0 -0
  100. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/matches.py +0 -0
  101. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/meta.py +0 -0
  102. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/ops.py +0 -0
  103. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/opto.py +0 -0
  104. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/parsing.py +0 -0
  105. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/utils.py +0 -0
  106. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/abnf/visitors.py +0 -0
  107. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/__init__.py +0 -0
  108. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/BufferedTokenStream.py +0 -0
  109. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/CommonTokenFactory.py +0 -0
  110. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/CommonTokenStream.py +0 -0
  111. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/FileStream.py +0 -0
  112. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/InputStream.py +0 -0
  113. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/IntervalSet.py +0 -0
  114. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/LICENSE.txt +0 -0
  115. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/LL1Analyzer.py +0 -0
  116. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/Lexer.py +0 -0
  117. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/ListTokenSource.py +0 -0
  118. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/Parser.py +0 -0
  119. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/ParserInterpreter.py +0 -0
  120. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/ParserRuleContext.py +0 -0
  121. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/PredictionContext.py +0 -0
  122. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/Recognizer.py +0 -0
  123. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/RuleContext.py +0 -0
  124. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/StdinStream.py +0 -0
  125. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/Token.py +0 -0
  126. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/TokenStreamRewriter.py +0 -0
  127. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/Utils.py +0 -0
  128. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/__init__.py +0 -0
  129. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/_all.py +0 -0
  130. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/_pygrun.py +0 -0
  131. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/ATN.py +0 -0
  132. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/ATNConfig.py +0 -0
  133. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/ATNConfigSet.py +0 -0
  134. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/ATNDeserializationOptions.py +0 -0
  135. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/ATNDeserializer.py +0 -0
  136. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/ATNSimulator.py +0 -0
  137. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/ATNState.py +0 -0
  138. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/ATNType.py +0 -0
  139. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/LexerATNSimulator.py +0 -0
  140. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/LexerAction.py +0 -0
  141. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/LexerActionExecutor.py +0 -0
  142. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/ParserATNSimulator.py +0 -0
  143. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/PredictionMode.py +0 -0
  144. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/SemanticContext.py +0 -0
  145. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/Transition.py +0 -0
  146. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/atn/__init__.py +0 -0
  147. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/dfa/DFA.py +0 -0
  148. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/dfa/DFASerializer.py +0 -0
  149. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/dfa/DFAState.py +0 -0
  150. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/dfa/__init__.py +0 -0
  151. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/error/DiagnosticErrorListener.py +0 -0
  152. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/error/ErrorListener.py +0 -0
  153. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/error/ErrorStrategy.py +0 -0
  154. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/error/Errors.py +0 -0
  155. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/error/__init__.py +0 -0
  156. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/tree/Chunk.py +0 -0
  157. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/tree/ParseTreeMatch.py +0 -0
  158. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/tree/ParseTreePattern.py +0 -0
  159. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/tree/ParseTreePatternMatcher.py +0 -0
  160. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/tree/RuleTagToken.py +0 -0
  161. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/tree/TokenTagToken.py +0 -0
  162. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/tree/Tree.py +0 -0
  163. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/tree/Trees.py +0 -0
  164. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/tree/__init__.py +0 -0
  165. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/xpath/XPath.py +0 -0
  166. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/xpath/XPathLexer.py +0 -0
  167. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/_runtime/xpath/__init__.py +0 -0
  168. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/cli/__main__.py +0 -0
  169. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/cli/cli.py +0 -0
  170. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/cli/consts.py +0 -0
  171. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/cli/gen.py +0 -0
  172. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/delimit.py +0 -0
  173. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/dot.py +0 -0
  174. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/errors.py +0 -0
  175. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/input.py +0 -0
  176. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/parsing.py +0 -0
  177. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/runtime.py +0 -0
  178. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra/text/antlr/utils.py +0 -0
  179. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra.egg-info/dependency_links.txt +0 -0
  180. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra.egg-info/entry_points.txt +0 -0
  181. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/omextra.egg-info/top_level.txt +0 -0
  182. {omextra-0.0.0.dev503 → omextra-0.0.0.dev505}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omextra
3
- Version: 0.0.0.dev503
3
+ Version: 0.0.0.dev505
4
4
  Summary: omextra
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Python: >=3.13
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
- Requires-Dist: omlish==0.0.0.dev503
17
+ Requires-Dist: omlish==0.0.0.dev505
18
18
  Dynamic: license-file
19
19
 
20
20
  # Overview
@@ -0,0 +1,253 @@
1
+ # Buffer System Design Notes — Historical Architecture Summary
2
+
3
+ This document captures the design rationale, constraints, and evolution of a **general-purpose byte buffer subsystem**
4
+ intended to support a **Netty-like, pipeline-oriented protocol toolkit in Python**. It is meant to serve as durable
5
+ architectural context for future development and onboarding, not as API documentation.
6
+
7
+ ---
8
+
9
+ ## 1. Problem Statement & Goals
10
+
11
+ The goal was to design a **foundational buffer layer** suitable for building protocol stacks in Python with the
12
+ following constraints:
13
+
14
+ - **Pure Python, no external dependencies**, compatible with Python 3.8+
15
+ - **Embeddable**: usable inside arbitrary runtimes (sync, async, fork-only, threaded, event-loop driven, or none at all)
16
+ - **Independent of asyncio / async-await**, but adaptable to them
17
+ - **Composable** and **pipeline-friendly**, favoring small chained transforms over large monolithic objects
18
+ - **Correctness and resilience first** (OOM avoidance, bounded growth, clear error signaling)
19
+ - **Low copy where possible**, but never at the expense of clarity or safety
20
+ - Explicitly **not performance-maximal**; Python-appropriate efficiency is sufficient
21
+
22
+ The buffer layer is treated as *infrastructure*: it must be robust enough that higher-level protocol code never needs to
23
+ second-guess its behavior.
24
+
25
+ ---
26
+
27
+ ## 2. Design Philosophy
28
+
29
+ ### Composition over inheritance Rather than building large stateful readers/writers, the design favors:
30
+ - Small buffer objects with explicit operations (`find`, `split_to`, `coalesce`, etc.)
31
+ - Stateless helper functions layered atop buffers (binary reads, framing, decoding)
32
+ - Pipeline codecs that operate purely on buffers + views
33
+
34
+ ### Explicit boundaries
35
+ - **Copy boundaries are explicit** (`tobytes`, `read_bytes`)
36
+ - **Mutation vs. presentation** is clearly distinguished
37
+ - **Ephemeral vs. stable views** are explicitly defined
38
+
39
+ ### “Everything needs a timeout / limit” All operations that can grow memory unboundedly must be limitable:
40
+ - Per-buffer `max_bytes`
41
+ - Per-frame `max_size`
42
+ - Clear error types when limits are exceeded
43
+
44
+ ---
45
+
46
+ ## 3. Core Abstractions
47
+
48
+ ### BytesBuffer (conceptual) A readable byte container with:
49
+ - Logical length (`__len__`)
50
+ - Search (`find`, `rfind`) — *stream-correct*, across internal segmentation
51
+ - Non-consuming inspection (`peek`, `segments`)
52
+ - Consuming operations (`advance`, `split_to`)
53
+ - Contiguity guarantee (`coalesce(n)`)
54
+
55
+ Buffers are **not sequences** and are **not random-access containers** in the general sense:
56
+ - They may support indexed access incidentally
57
+ - But they are optimized for *prefix-oriented, streaming access*
58
+ - They are not intended for arbitrary slicing or mutation
59
+
60
+ ---
61
+
62
+ ## 4. Two Concrete Buffer Backends
63
+
64
+ ### SegmentedBytesBuffer A list-of-segments design (bytes / bytearray chunks):
65
+
66
+ **Strengths**
67
+ - Avoids pathological “large buffer pinned by tiny tail”
68
+ - Stable zero-copy views for `split_to`
69
+ - Natural fit for network chunking and streaming
70
+
71
+ **Tradeoffs**
72
+ - Search and coalescing require careful logic
73
+ - Segment count must be managed (coalescing / heuristics)
74
+
75
+ ### LinearBytesBuffer A single `bytearray` + read/write indices:
76
+
77
+ **Strengths**
78
+ - Fast scanning and header parsing
79
+ - Naturally contiguous prefix
80
+ - Efficient `reserve` / `commit`
81
+
82
+ **Tradeoffs**
83
+ - `split_to` must copy to keep views stable
84
+ - Needs compaction heuristics to avoid growth from head advancement
85
+
86
+ These two backends intentionally cover different workload shapes; both conform to the same conceptual interface.
87
+
88
+ ---
89
+
90
+ ## 5. Views & Lifetime Rules
91
+
92
+ ### BytesView / SegmentedBytesView Objects returned from `split_to`:
93
+ - Represent bytes **removed** from the buffer
94
+ - Must remain **stable forever**
95
+ - May internally reference original segments or copies
96
+
97
+ ### Ephemeral views Returned from:
98
+ - `peek`
99
+ - `segments`
100
+ - `coalesce`
101
+
102
+ Rules:
103
+ - Valid only until the next buffer mutation
104
+ - Never safe to hold across writes / advances
105
+ - Always exposed as `memoryview`
106
+
107
+ This mirrors real-world behavior in systems like Netty (retained slices) but without refcounting.
108
+
109
+ ---
110
+
111
+ ## 6. Coalescing Semantics (Key Design Point)
112
+
113
+ ### `coalesce(n)` Guarantees the first `n` readable bytes are contiguous.
114
+
115
+ - **Non-consuming**
116
+ - May restructure internal storage
117
+ - Copies *only if necessary*, and only the minimal prefix
118
+ - Disallowed while a reservation is outstanding
119
+
120
+ Rationale:
121
+ - Python lacks efficient per-byte iteration
122
+ - Many operations (binary parsing, decoding) require contiguity
123
+ - Copying should happen *close to storage*, not in higher-level code
124
+
125
+ Unlike Netty or Tokio (where coalescing is implicit or pattern-based), this is an explicit primitive.
126
+
127
+ ---
128
+
129
+ ## 7. Reservation Model (`reserve` / `commit`)
130
+
131
+ Designed to support:
132
+ - Zero-copy reads from drivers
133
+ - Predictable memory behavior
134
+
135
+ Rules:
136
+ - Only one outstanding reservation at a time
137
+ - While reserved:
138
+ - No reshaping operations allowed
139
+ - No coalescing, splitting, advancing, or writing
140
+ - `commit(n)` appends exactly `n` bytes
141
+ - Reservation buffers are **temporary**, not views into live storage
142
+ - Avoids Python `BufferError` pinning issues
143
+
144
+ This design was informed directly by pitfalls discovered when using `BytesIO.getbuffer()`.
145
+
146
+ ---
147
+
148
+ ## 8. Limits & Error Taxonomy
149
+
150
+ ### Core error types
151
+ - `NeedMoreData`: insufficient bytes, retry later
152
+ - `BufferTooLarge`: buffer growth exceeded cap
153
+ - `FrameTooLarge`: single frame exceeded size limit
154
+ - `OutstandingReserve` / `NoOutstandingReserve`: invalid state transitions
155
+
156
+ Design choice:
157
+ - Limit errors subclass `ValueError`
158
+ - State errors subclass `RuntimeError`
159
+ - Preserves compatibility while enabling semantic distinction
160
+
161
+ ### Limits
162
+ - `max_bytes` on buffers (optional, default None)
163
+ - `max_size` on framers/codecs
164
+
165
+ These limits are enforced eagerly to prevent memory exhaustion.
166
+
167
+ ---
168
+
169
+ ## 9. Framing & Search
170
+
171
+ ### Longest-match delimiter framing A dedicated codec layer implements:
172
+ - Overlapping delimiters (`\r` vs `\r\n`)
173
+ - Longest-match semantics
174
+ - Deferred emission when ambiguity exists
175
+ - Explicit `final=True` flush at EOF
176
+
177
+ Key insight: > Delimiter resolution must live *above* the buffer but *below* protocol logic.
178
+
179
+ The buffer’s `find/rfind` remain simple, single-needle primitives; framing logic resolves ambiguity.
180
+
181
+ ---
182
+
183
+ ## 10. Binary Read Helpers
184
+
185
+ Implemented as **pure functions atop buffers**, not methods:
186
+ - `peek_exact`
187
+ - `take`
188
+ - `read_bytes`
189
+ - `read_u8`, `read_u16_be`, `read_u32_le`, etc.
190
+
191
+ All rely on:
192
+ - `coalesce(n)` for contiguity
193
+ - `advance(n)` for consumption
194
+ - `NeedMoreData` for retry signaling
195
+
196
+ This keeps the buffer surface small while enabling rich protocol parsing.
197
+
198
+ ---
199
+
200
+ ## 11. File-Like Adapters & Interop
201
+
202
+ Adapters exist to bridge:
203
+ - File-like objects → buffers
204
+ - Buffers → file-like readers/writers
205
+
206
+ Key properties:
207
+ - Policy-driven behavior (`raise`, `return_partial`, `block`)
208
+ - No reliance on `io` abstractions in the core
209
+ - Explicit handling of `BytesIO.getbuffer()` pinning hazards
210
+
211
+ Interop is intentionally *ugly but isolated*; the core remains clean.
212
+
213
+ ---
214
+
215
+ ## 12. Relation to Other Ecosystems
216
+
217
+ ### Netty
218
+ - Netty’s buffer complexity is split across many types (heap, direct, composite)
219
+ - This design captures the *behavioral essence* (segmentation, coalescing, stable views) without refcounting
220
+
221
+ ### Tokio / Rust
222
+ - Similar semantics exist implicitly (`Buf::chunk`, `advance`)
223
+ - Python benefits from explicit coalescing due to higher call overhead
224
+
225
+ ### Twisted / asyncio
226
+ - Older designs rely on callbacks and file-like objects
227
+ - This system is explicitly designed *post-async/await*, but not dependent on it
228
+
229
+ ---
230
+
231
+ ## 13. What This Enables Next
232
+
233
+ With the buffer layer stabilized, higher-level work can proceed safely:
234
+ - Length-prefixed framing
235
+ - HTTP/1 streaming parsing
236
+ - Binary protocol codecs
237
+ - Pipeline lifecycle (EOF, errors, close)
238
+ - Transport drivers (async, sync, custom)
239
+
240
+ The buffer layer is now considered **foundationally complete**: additional features should be justified by concrete
241
+ protocol needs, not speculation.
242
+
243
+ ---
244
+
245
+ ## 14. Key Takeaway
246
+
247
+ This buffer system is intentionally:
248
+ - **Explicit**, not magical
249
+ - **Predictable**, not clever
250
+ - **Composable**, not monolithic
251
+
252
+ It trades a small amount of convenience for long-term correctness and clarity — exactly what is needed to support a
253
+ robust, Netty-like protocol toolkit in Python.
@@ -0,0 +1,294 @@
1
+ # ruff: noqa: UP006 UP007 UP045
2
+ # @omlish-lite
3
+ import io
4
+ import time
5
+ import typing as ta
6
+
7
+ from .errors import NeedMoreData
8
+ from .segmented import SegmentedBytesView
9
+ from .types import BytesLike
10
+ from .types import BytesView
11
+ from .types import BytesViewLike
12
+
13
+
14
+ ##
15
+
16
+
17
+ class FileLikeRawBytesReader:
18
+ """
19
+ Adapter: file-like object -> RawBytesReader-style `read1`.
20
+
21
+ This is intentionally permissive: it duck-types common file-like APIs.
22
+
23
+ Notes:
24
+ - If the object has `read1`, we use it.
25
+ - Otherwise we fall back to `read`.
26
+ - This is a *raw* reader: it makes no buffering guarantees beyond what the wrapped object provides.
27
+ """
28
+
29
+ def __init__(self, f: ta.Any) -> None:
30
+ super().__init__()
31
+
32
+ self._f = f
33
+
34
+ def read1(self, n: int = -1, /) -> bytes:
35
+ f = self._f
36
+ if hasattr(f, 'read1'):
37
+ return ta.cast(bytes, f.read1(n))
38
+ return ta.cast(bytes, f.read(n))
39
+
40
+
41
+ class FileLikeBufferedBytesReader(FileLikeRawBytesReader):
42
+ """
43
+ Adapter: file-like object -> BufferedBytesReader-style `read/readall`.
44
+
45
+ Notes:
46
+ - Uses `readall` if present; otherwise uses `read()` with `-1`.
47
+ - Does not impose additional buffering; it reflects the wrapped object's behavior.
48
+ """
49
+
50
+ def read(self, n: int = -1, /) -> bytes:
51
+ return ta.cast(bytes, self._f.read(n))
52
+
53
+ def readall(self) -> bytes:
54
+ f = self._f
55
+ if hasattr(f, 'readall'):
56
+ return ta.cast(bytes, f.readall())
57
+ return ta.cast(bytes, f.read())
58
+
59
+
60
+ class BytesBufferReaderAdapter:
61
+ """
62
+ Adapter: BytesBuffer -> file-like reader methods (`read1`, `read`, `readall`).
63
+
64
+ This adapter is policy-driven for how it behaves when insufficient bytes are available. The core buffer is
65
+ intentionally non-blocking; blocking behavior (if desired) must be provided via a `fill` callback that supplies more
66
+ bytes into the buffer.
67
+
68
+ `policy`:
69
+ - 'raise': raise NeedMoreData if fewer than `n` bytes are available (for n >= 0).
70
+ - 'return_partial': return whatever is available (possibly b'') up to `n`.
71
+ - 'block': repeatedly call `fill()` until satisfied or until `fill()` signals EOF.
72
+
73
+ `fill`:
74
+ - Callable that writes more bytes into the underlying MutableBytesBuffer and returns:
75
+ * True -> made progress / more data may be available
76
+ * False -> EOF / no more data will arrive
77
+ - Only used when policy == 'block'.
78
+
79
+ This adapter exists for interop with legacy code that expects file-like objects, but the core design remains
80
+ independent from `io` and blocking semantics.
81
+ """
82
+
83
+ def __init__(
84
+ self,
85
+ buf: ta.Any,
86
+ *,
87
+ policy: ta.Literal['raise', 'return_partial', 'block'] = 'raise',
88
+ fill: ta.Optional[ta.Callable[[], bool]] = None,
89
+ block_sleep: ta.Union[ta.Callable[[], None], float, None] = None,
90
+ ) -> None:
91
+ super().__init__()
92
+
93
+ self._buf = buf
94
+ self._policy = policy
95
+ self._fill = fill
96
+ self._block_sleep = block_sleep
97
+
98
+ if self._policy == 'block' and self._fill is None:
99
+ raise ValueError('policy=block requires fill')
100
+
101
+ def _on_block(self) -> None:
102
+ if (bs := self._block_sleep) is None:
103
+ return
104
+ elif callable(bs):
105
+ bs()
106
+ else:
107
+ time.sleep(bs)
108
+
109
+ def read1(self, n: int = -1, /) -> bytes:
110
+ return self.read(n)
111
+
112
+ def read(self, n: int = -1, /) -> bytes:
113
+ buf = self._buf
114
+
115
+ if n is None or n < 0:
116
+ return self.readall()
117
+
118
+ if n == 0:
119
+ return b''
120
+
121
+ while True:
122
+ ln = len(buf)
123
+ if ln >= n:
124
+ v = buf.split_to(n)
125
+ return ta.cast(bytes, v.tobytes())
126
+
127
+ if self._policy == 'return_partial':
128
+ if ln == 0:
129
+ return b''
130
+ v = buf.split_to(ln)
131
+ return ta.cast(bytes, v.tobytes())
132
+
133
+ if self._policy == 'raise':
134
+ raise NeedMoreData
135
+
136
+ # block
137
+ if not ta.cast('ta.Callable[[], bool]', self._fill)():
138
+ # EOF
139
+ if ln == 0:
140
+ return b''
141
+ v = buf.split_to(ln)
142
+ return ta.cast(bytes, v.tobytes())
143
+
144
+ self._on_block()
145
+
146
+ def readall(self) -> bytes:
147
+ buf = self._buf
148
+ parts: ta.List[bytes] = []
149
+
150
+ while True:
151
+ ln = len(buf)
152
+ if ln:
153
+ v = buf.split_to(ln)
154
+ parts.append(ta.cast(bytes, v.tobytes()))
155
+ continue
156
+
157
+ if self._policy == 'block':
158
+ if not ta.cast('ta.Callable[[], bool]', self._fill)():
159
+ break
160
+ self._on_block()
161
+ continue
162
+
163
+ break
164
+
165
+ return b''.join(parts)
166
+
167
+
168
+ class BytesBufferWriterAdapter:
169
+ """
170
+ Adapter: file-like writer sink <- BytesBuffer / bytes-like.
171
+
172
+ This is intentionally small and dumb: it exists to bridge into code expecting a `.write(...)`
173
+ method on an object.
174
+
175
+ If given a BytesView-like object, it writes segment-by-segment to avoid materializing copies
176
+ when the sink can accept multiple writes efficiently.
177
+ """
178
+
179
+ def __init__(self, f: ta.Any) -> None:
180
+ super().__init__()
181
+
182
+ self._f = f
183
+
184
+ def write(self, data: ta.Any) -> int:
185
+ f = self._f
186
+
187
+ if isinstance(data, (bytes, bytearray, memoryview)):
188
+ b = data.tobytes() if isinstance(data, memoryview) else bytes(data)
189
+ return ta.cast(int, f.write(b))
190
+
191
+ if isinstance(data, BytesViewLike):
192
+ total = 0
193
+ for mv in data.segments():
194
+ total += ta.cast(int, f.write(bytes(mv)))
195
+ return total
196
+
197
+ if isinstance(data, BytesView):
198
+ b = data.tobytes()
199
+ return ta.cast(int, f.write(b))
200
+
201
+ raise TypeError(data)
202
+
203
+
204
+ class BytesIoBytesBuffer:
205
+ """
206
+ BytesBuffer/MutableBytesBuffer implementation backed by `io.BytesIO`, using `getbuffer()`.
207
+
208
+ This exists primarily for interoperability with code that already produces/consumes `BytesIO`,
209
+ and to demonstrate how `getbuffer()` can expose a non-copying `memoryview` of internal storage.
210
+
211
+ Caveat (important):
212
+ - Any exported `memoryview` from `BytesIO.getbuffer()` can pin the BytesIO against resizing.
213
+ - If a caller holds onto a view and we attempt to grow/resize internally, `BytesIO` may raise
214
+ `BufferError`. We surface that as a RuntimeError.
215
+
216
+ This backing is therefore best suited for controlled scenarios; it is *not* the recommended
217
+ default buffer backend for pynetty (segmented/bytearray backends are more predictable).
218
+ """
219
+
220
+ def __init__(self) -> None:
221
+ super().__init__()
222
+
223
+ self._bio = io.BytesIO()
224
+ self._rpos = 0
225
+
226
+ # reserve/commit state
227
+ self._resv: ta.Optional[bytearray] = None
228
+ self._resv_len = 0
229
+
230
+ def __len__(self) -> int:
231
+ return self._bio.getbuffer().nbytes - self._rpos
232
+
233
+ def peek(self) -> memoryview:
234
+ mv = self._bio.getbuffer()
235
+ return mv[self._rpos:]
236
+
237
+ def segments(self) -> ta.Sequence[memoryview]:
238
+ mv = self._bio.getbuffer()
239
+ seg = mv[self._rpos:]
240
+ return (seg,) if len(seg) else ()
241
+
242
+ def advance(self, n: int, /) -> None:
243
+ if n < 0 or n > len(self):
244
+ raise ValueError(n)
245
+ self._rpos += n
246
+ # Optional compaction heuristic: if we've consumed a lot, rebuild a smaller BytesIO.
247
+ # This may fail if someone holds a getbuffer() view (BufferError).
248
+ if self._rpos and self._rpos >= 65536 and self._rpos >= (self._bio.getbuffer().nbytes // 2):
249
+ try:
250
+ remaining = self._bio.getbuffer()[self._rpos:].tobytes()
251
+ self._bio = io.BytesIO(remaining)
252
+ self._rpos = 0
253
+ except BufferError as e:
254
+ raise RuntimeError('BytesIO buffer is pinned by an exported view') from e
255
+
256
+ def split_to(self, n: int, /) -> SegmentedBytesView:
257
+ if n < 0 or n > len(self):
258
+ raise ValueError(n)
259
+ mv = self._bio.getbuffer()
260
+ out = mv[self._rpos:self._rpos + n]
261
+ self._rpos += n
262
+ return SegmentedBytesView((out,))
263
+
264
+ def write(self, data: BytesLike, /) -> None:
265
+ if not data:
266
+ return
267
+ if isinstance(data, memoryview):
268
+ data = data.tobytes()
269
+ try:
270
+ self._bio.seek(0, io.SEEK_END)
271
+ self._bio.write(ta.cast(bytes, data))
272
+ except BufferError as e:
273
+ raise RuntimeError('BytesIO buffer is pinned by an exported view') from e
274
+
275
+ def reserve(self, n: int, /) -> memoryview:
276
+ if n < 0:
277
+ raise ValueError(n)
278
+ if self._resv is not None:
279
+ raise RuntimeError('outstanding reserve')
280
+ b = bytearray(n)
281
+ self._resv = b
282
+ self._resv_len = n
283
+ return memoryview(b)
284
+
285
+ def commit(self, n: int, /) -> None:
286
+ if self._resv is None:
287
+ raise RuntimeError('no outstanding reserve')
288
+ if n < 0 or n > self._resv_len:
289
+ raise ValueError(n)
290
+ b = self._resv
291
+ self._resv = None
292
+ self._resv_len = 0
293
+ if n:
294
+ self.write(memoryview(b)[:n])
@@ -0,0 +1,63 @@
1
+ from .adapters import ( # noqa
2
+ FileLikeRawBytesReader,
3
+ FileLikeBufferedBytesReader,
4
+ BytesBufferReaderAdapter,
5
+ BytesBufferWriterAdapter,
6
+ BytesIoBytesBuffer,
7
+ )
8
+
9
+ from .errors import ( # noqa
10
+ BuffersError,
11
+ NeedMoreData,
12
+ BufferLimitError,
13
+ BufferTooLarge,
14
+ FrameTooLarge,
15
+ BufferStateError,
16
+ OutstandingReserve,
17
+ NoOutstandingReserve,
18
+ )
19
+
20
+ from .framing import ( # noqa
21
+ LongestMatchDelimiterFramer,
22
+ )
23
+
24
+ from .linear import ( # noqa
25
+ LinearBytesBuffer,
26
+ )
27
+
28
+ from .reading import ( # noqa
29
+ peek_u8,
30
+ read_u8,
31
+ peek_u16_be,
32
+ read_u16_be,
33
+ peek_u16_le,
34
+ read_u16_le,
35
+ peek_u32_be,
36
+ read_u32_be,
37
+ peek_u32_le,
38
+ read_u32_le,
39
+ )
40
+
41
+ from .scanning import ( # noqa
42
+ ScanningBytesBuffer,
43
+ )
44
+
45
+ from .segmented import ( # noqa
46
+ SegmentedBytesView,
47
+ SegmentedBytesBuffer,
48
+ )
49
+
50
+ from .types import ( # noqa
51
+ BytesLike,
52
+
53
+ BytesView,
54
+ BytesBuffer,
55
+ MutableBytesBuffer,
56
+ )
57
+
58
+ from .utils import ( # noqa
59
+ can_bytes,
60
+ iter_bytes_segments,
61
+ to_bytes,
62
+ bytes_len,
63
+ )
@@ -0,0 +1,54 @@
1
+ # @omlish-lite
2
+
3
+
4
+ ##
5
+
6
+
7
+ class BuffersError(Exception):
8
+ pass
9
+
10
+
11
+ class NeedMoreData(BuffersError): # noqa
12
+ """
13
+ Raised when an operation cannot complete because insufficient bytes are currently buffered.
14
+
15
+ This is intentionally distinct from EOF: it means "try again after feeding more bytes".
16
+ """
17
+
18
+
19
+ class BufferLimitError(ValueError, BuffersError): # noqa
20
+ """
21
+ Base class for buffer/framing limit violations.
22
+
23
+ Subclasses inherit from ValueError so existing tests expecting ValueError continue to pass.
24
+ """
25
+
26
+
27
+ class BufferTooLarge(BufferLimitError): # noqa
28
+ """
29
+ Buffered data exceeded a configured cap without finding a boundary that would allow progress.
30
+
31
+ Typically indicates an unframed stream, a missing delimiter, or an upstream not enforcing limits.
32
+ """
33
+
34
+
35
+ class FrameTooLarge(BufferLimitError): # noqa
36
+ """
37
+ A single decoded frame (payload before its boundary delimiter/length) exceeded a configured max size.
38
+ """
39
+
40
+
41
+ class BufferStateError(RuntimeError, BuffersError): # noqa
42
+ """
43
+ Base class for invalid buffer state transitions (e.g., coalescing while a reservation is outstanding).
44
+
45
+ Subclasses inherit from RuntimeError so existing tests expecting RuntimeError continue to pass.
46
+ """
47
+
48
+
49
+ class OutstandingReserve(BufferStateError): # noqa
50
+ """A reserve() is outstanding; an operation requiring stable storage cannot proceed."""
51
+
52
+
53
+ class NoOutstandingReserve(BufferStateError): # noqa
54
+ """commit() was called without a preceding reserve()."""