This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git


The following commit(s) were added to refs/heads/main by this push:
     new 24fdb9b0a chore: clean unnecessary buffer checks (#3988)
24fdb9b0a is described below

commit 24fdb9b0a83e672578683cb72c2607710bdd5073
Author: Shawn Yang <[email protected]>
AuthorDate: Thu Aug 27 13:18:23 2026 +0800

    chore: clean unnecessary buffer checks (#3988)
    
    ## Why?
    
    
    
    ## What does this PR do?
    
    
    
    ## Related issues
    
    #3987
    
    ## AI Contribution Checklist
    
    
    
    - [ ] Substantial AI assistance was used in this PR: `yes` / `no`
    - [ ] If `yes`, I included a completed [AI Contribution
    
Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs)
    in this PR description and the required `AI Usage Disclosure`.
    - [ ] If `yes`, my PR description includes the required `ai_review`
    summary and screenshot evidence or equivalent persisted links of the
    final clean AI review results from both fresh reviewers described in
    `AI_POLICY.md`, the Fory-guided reviewer and the independent general
    reviewer, on the current PR diff or current HEAD after the latest code
    changes.
    
    
    
    ## Does this PR introduce any user-facing change?
    
    
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
    
    ---------
    
    Co-authored-by: Release Validation Test <[email protected]>
---
 .agents/languages/cpp.md                           |  11 +-
 .agents/languages/go.md                            |  11 +-
 .agents/languages/java.md                          |  29 +-
 AGENTS.md                                          |  50 +--
 cpp/fory/serialization/array_serializer.h          |  18 +-
 cpp/fory/serialization/collection_serializer.h     |  85 ++---
 cpp/fory/serialization/serialization_test.cc       |   2 +-
 cpp/fory/serialization/string_serializer.h         |  19 +-
 cpp/fory/serialization/struct_serializer.h         |  69 ++--
 cpp/fory/serialization/unsigned_serializer.h       |  44 +--
 cpp/fory/util/buffer.h                             | 326 +++++++-----------
 cpp/fory/util/buffer_test.cc                       |  53 +--
 docs/security/deserialization.md                   |   8 -
 .../src/main/java/org/apache/fory/Fory.java        |  14 +-
 .../java/org/apache/fory/memory/MemoryBuffer.java  | 382 ++++++++++++++-------
 .../fory/serializer/PrimitiveArraySerializers.java | 236 +------------
 .../org/apache/fory/memory/MemoryBuffer.java       | 189 ++++++++--
 .../org/apache/fory/memory/MemoryBufferTest.java   | 114 ++++--
 python/pyfory/cpp/pyfory.cc                        |   4 +-
 python/pyfory/number.pxi                           |  13 -
 python/pyfory/tests/test_buffer.py                 |  37 --
 rust/fory-core/src/buffer.rs                       |   1 +
 rust/tests/tests/test_buffer.rs                    |   5 +
 swift/Sources/Fory/ByteBuffer.swift                |  13 +-
 24 files changed, 824 insertions(+), 909 deletions(-)

diff --git a/.agents/languages/cpp.md b/.agents/languages/cpp.md
index 1b3780eba..c5a45fa41 100644
--- a/.agents/languages/cpp.md
+++ b/.agents/languages/cpp.md
@@ -13,12 +13,11 @@ Load this file when changing `cpp/`, Cython build plumbing, 
or C++ xlang behavio
 - When invoking a method that returns `Result`, use `FORY_TRY` unless you are 
in control-flow logic that cannot use it cleanly.
 - Wrap error checks with `FORY_PREDICT_FALSE` for branch prediction.
 - Continue on trivial errors; return early only for critical errors such as 
buffer overflow.
-- `ReadContext` and related codec owners intentionally accumulate non-critical
-  errors and inspect them at established serializer or root safepoints. 
Bounds-safe
-  work may continue after an error is recorded. Do not add eager per-field 
checks,
-  cursor rollback, or tests that pin the first detection point unless deferral 
can
-  cause out-of-bounds access, undefined behavior, resource amplification, state
-  pollution, or success past the required safepoint.
+- `ReadContext` intentionally records codec errors for inspection at existing 
serializer or root
+  safepoints. After an error, work may continue only while it remains 
bounds-safe and cannot cause
+  resource amplification, publish reference or cache state that survives root 
cleanup, or return
+  success past the required safepoint. Do not add per-field checks, cursor 
rollback, or tests that
+  pin the first detection point solely to make an error earlier or more 
precise.
 - Put private methods last in class definitions, immediately before private 
fields.
 - Do not redesign alias-based or low-level public type shapes to add 
convenience methods unless the user explicitly asks for that API change.
 - For cross-language feature ports, match protocol behavior but use idiomatic 
C++ ownership and layering instead of mirroring Java structure literally.
diff --git a/.agents/languages/go.md b/.agents/languages/go.md
index a8256d74d..5192fc3e7 100644
--- a/.agents/languages/go.md
+++ b/.agents/languages/go.md
@@ -7,12 +7,11 @@ Load this file when changing `go/fory/` or Go xlang behavior.
 - Run Go commands from within `go/fory/`.
 - Changes under `go/` must pass formatting and tests.
 - The Go implementation focuses on fast serializers.
-- Go codec paths may intentionally record an error and continue bounds-safe 
work
-  until an established serializer or root safepoint checks it. Do not add eager
-  per-field or per-element error branches, cursor rollback, or tests that pin 
the
-  first detection point unless deferral can cause a panic, out-of-bounds 
access,
-  disproportionate work or allocation, persistent state pollution, or success
-  past the required safepoint.
+- Go `ReadContext` intentionally defers codec errors to existing `HasError` or 
`CheckError`
+  boundaries. After an error, work may continue only while it remains panic- 
and bounds-safe and
+  cannot cause disproportionate work or allocation, publish state that 
survives root cleanup, or
+  return success past the required boundary. Do not add per-field or 
per-element checks, cursor
+  rollback, or tests that pin the first detection point solely to change error 
timing or precision.
 - Root deserialization graph memory budget state belongs to `ReadContext`.
   `WithMaxGraphMemoryBytes` uses a fixed `128 MiB` default; positive explicit
   values override it, and explicit non-positive values are invalid at config 
creation.
diff --git a/.agents/languages/java.md b/.agents/languages/java.md
index 00d5553c0..a96d04b7f 100644
--- a/.agents/languages/java.md
+++ b/.agents/languages/java.md
@@ -159,22 +159,27 @@ Load this file when changing anything under `java/` or 
when Java drives a cross-
 - In `MemoryBuffer` and `MemoryOps` hot paths, duplicate small straight-line 
copy/read/write logic
   when that keeps control flow direct. Do not add private helper indirection 
to hot paths just to
   reduce local code duplication; keep helpers for slow, cold, or error paths.
+- `MemoryBuffer` semantic primitive-array `write*` and `read*` methods own the 
canonical
+  little-endian element order. Keep native bulk copy as the little-endian hot 
path and isolate
+  big-endian conversion in separate slow helpers; serializers must not 
duplicate that endian
+  branch. The explicit `copyTo*Array` and `copyFrom*Array` methods remain raw 
native-memory copies,
+  so their format owner must handle byte order when required.
 - Add a Java `MemoryBuffer` check only when its absence can cause a JVM or 
native crash, OOM, or
   attacker-controlled memory amplification. Delayed, masked, less precise, or 
differently typed
   failures do not justify a check, and neither does an incorrect decoded 
result without one of
-  those crash or memory consequences. Do not duplicate an array, `ByteBuffer`, 
VarHandle, stream,
+  those crash or memory consequences. Do not duplicate an array, `ByteBuffer`, 
`VarHandle`, stream,
   or other existing bounds owner merely to move or normalize an error.
-- The JDK 25 `MemoryBuffer` overlay is intentionally unchecked at its logical 
buffer boundary.
-  Indexed array accesses, absolute `ByteBuffer` accesses, and VarHandle 
accesses own bounds
-  enforcement and already provide a controlled failure; its exact exception 
type, message, and
-  detection point are not contracts. Do not copy the JDK 8-24 Unsafe-path 
range checks into this
-  overlay. Keep an explicit check only before allocation, capacity growth, or 
another side effect
-  when it is required to prevent a crash, OOM, or attacker-controlled memory 
amplification that the
-  access owner cannot contain.
-- `MemoryAllocator.grow` owns the postcondition that a successful return has 
supplied at least the
-  requested capacity. `MemoryBuffer` must not recheck that postcondition after 
calling `grow` or
-  `ensure`; an allocator that returns without satisfying it violates the 
allocator contract and
-  must be fixed in the allocator implementation rather than burdening every 
buffer hot path.
+- The JDK 25 `MemoryBuffer` overlay intentionally does not duplicate logical 
range checks around
+  indexed array, absolute `ByteBuffer`, or `VarHandle` access. Those JVM 
accessors own physical
+  bounds enforcement and already provide a controlled failure; the exact 
exception type, message,
+  and detection point are not contracts. Do not copy JDK 8-24 Unsafe-path 
checks into the overlay
+  solely to make invalid access fail earlier or more precisely. Keep an 
explicit check before
+  allocation, capacity growth, or another side effect when it is needed to 
prevent a crash, OOM, or
+  attacker-controlled memory amplification that the access owner cannot 
contain.
+- `MemoryAllocator.grow` owns the postcondition that a successful return 
leaves the buffer capacity
+  at least the requested capacity. Callers must reject invalid or overflowed 
requests before the
+  call, but must not recheck the allocator postcondition afterward; fix a 
violating allocator at
+  the allocator implementation.
 - In JDK 25 Fory JSON C2-sensitive code, preserve measured, naturally large 
hot-method boundaries.
   A method that exceeds HotSpot's 325-byte hot-inline limit through real 
representation, scalar,
   array, collection, or generated-schema work is an independent subtree owner. 
Generated group
diff --git a/AGENTS.md b/AGENTS.md
index 680f992a5..10f82994a 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -32,6 +32,13 @@ This is the entry point for AI guidance in Apache Fory. Read 
this file first, th
 - Preserve architecture. Do not introduce new layers, parallel flows, or 
public APIs unless explicitly requested; prefer local repair in the existing 
owner over shared-infra expansion, and stop if a fix conflicts with an ADR, 
spec, or invariant.
 - Do not change an existing `RefReader`/`RefWriter` architecture or API to 
support compatible skip. Compatible skip must not add alternate reference slots 
or tables, alternate reference lookup or publication methods, or forwarding 
APIs in read/write contexts, builders, serializers, or generated-code plumbing. 
Keep ordinary reference publication and lookup unchanged and resolve the case 
in the existing compatible generated owner. For an authorized removed-field 
read of an unregistered Str [...]
 - Respect ownership. Keep logic, state, and helpers in their natural owner, 
and do not move serializer-local, context-local, runtime-type-local, or 
protocol-local problems into global utilities.
+- Low-level APIs explicitly named `unsafe` or `unchecked` may be public and 
may omit local bounds or
+  capacity checks. Their callers own the proof required by the operation. Do 
not hide these APIs
+  behind private access, checked forwarding wrappers, friend adapters, or 
duplicate implementations
+  solely to prevent misuse; add validation only at the caller or owner that 
lacks the required proof.
+- Keep hardening changes causal. A shared wire defect may require aligned 
runtime fixes, but it does
+  not justify unrelated buffer checks, performance rewrites, or cleanup 
without their own concrete
+  consequence and evidence.
 - Check the spec before implementation. For wire behavior and xlang mapping, 
use the specs as the source of truth and never copy one runtime's bug into 
another runtime just to make tests pass.
 - `foryc` is a build-time compiler for trusted schema inputs and is never 
invoked by runtime serialization or deserialization. Schema provenance, 
package/namespace options, output-path options, and generated-source review 
belong to the application or build owner. Do not classify hostile-schema source 
injection or path traversal as a Fory runtime security vulnerability; `foryc` 
does not promise to sandbox untrusted schemas.
 - Row format accepts only trusted input and is outside Fory's untrusted 
binary-deserialization security boundary. Rust `check_string_read(false)` is 
likewise an explicit trusted-input mode that disables UTF-8 validation; its 
caller owns the validity guarantee. Classify issues in those paths as 
correctness, soundness, or hardening bugs when applicable, not as 
attacker-controlled deserialization vulnerabilities under the default security 
model.
@@ -40,25 +47,13 @@ This is the entry point for AI guidance in Apache Fory. 
Read this file first, th
 - Malformed input must surface as a controlled root-operation error and still 
run
   root cleanup, but the exact exception type, error code, message, detection
   layer, and detection point are not contracts unless a public API or
-  specification explicitly says otherwise. An existing bounded downstream
-  buffer, type, reference, depth, or serializer error is sufficient. Do not add
+  specification explicitly says otherwise. Differences only in error type,
+  message, layer, offset, or detection point are not security findings. An
+  existing bounded downstream buffer, type, reference, depth, or serializer
+  error is sufficient. Do not add
   hot-path branches, helper APIs, allocations, or generated-code expansion
   solely to make an error earlier, more specific, or more uniform, and do not
   write tests that force such error normalization.
-- Non-strict, non-precise, delayed, masked, differently typed, or differently 
layered controlled
-  errors are not security findings. Security remediation must not add checks 
solely to normalize,
-  sharpen, advance, or otherwise make such errors deterministic. Security 
tests must not require a
-  particular error type, message, layer, offset, or detection point unless an 
explicit public
-  contract makes that precision part of the policy boundary.
-- Runtimes with an established lazy-error accumulator, including C++ and Go,
-  may keep executing bounds-safe codec work after recording an error and 
inspect
-  it at an existing serializer or root-operation safepoint. Deferred inspection
-  is an intentional hot-path design, not by itself a correctness or security
-  defect. Do not add per-field or per-element error branches, cursor rollback,
-  or tests that require immediate propagation solely because an earlier check 
is
-  possible. Treat the behavior as a defect only when the deferred path has a
-  concrete consequence listed below or an established safepoint can return
-  success instead of a controlled root error.
 - Never add a reader-side check solely to produce a more precise 
malformed-input
   error. Retain or add a check only when the unchecked path has a concrete
   consequence such as a crash, panic, undefined behavior, out-of-bounds access,
@@ -69,15 +64,6 @@ This is the entry point for AI guidance in Apache Fory. Read 
this file first, th
   helper when the language supports it. A bounds-safe downstream operation that
   already raises a controlled root error is sufficient; do not duplicate it for
   error precision.
-- Buffer and memory-buffer checks require a stricter consequence test. 
Security remediation may add
-  a check only when its absence can cause a process crash or panic, undefined 
memory access, OOM, or
-  attacker-controlled memory amplification. Delayed, masked, less precise, or 
differently typed
-  errors are not sufficient reasons. Neither is an incorrect decoded result 
when the unchecked
-  path cannot cause one of those crash or memory consequences. A downstream 
bounds owner that
-  already fails in a controlled way is sufficient; do not duplicate its check 
in a hotter wrapper.
-  Apply this admission rule prospectively: do not remove an already completed 
and validated check
-  solely by reclassifying it when it has no demonstrated performance cost. 
Preserve that check as
-  a correctness fix unless an explicit task requires the behavioral rollback.
 - Before reporting or fixing a robustness finding, prove that the current path
   causes at least one concrete consequence: crash, panic, undefined behavior,
   or out-of-bounds access; disproportionate allocation, CPU work, or stream
@@ -88,16 +74,6 @@ This is the entry point for AI guidance in Apache Fory. Read 
this file first, th
   malformed or noncanonical flag, enum value, marker, length form, or reserved
   value is accepted, rejected late, decoded differently, or produces a less
   precise error.
-- Keep security remediation scope frozen. Do not fix a standalone non-security
-  correctness, interoperability, API, or lifecycle issue merely because it is
-  discovered during security work. Include an adjacent non-security change only
-  when omitting it would leave the security fix incomplete or force the same
-  owner into an ugly, duplicated, or knowingly unsound design; otherwise record
-  the issue separately and leave production code unchanged. This rule prevents
-  new scope; it does not authorize rolling back a non-security fix that is
-  already implemented and validated. Preserve such fixes. If one may affect
-  performance, inspect and measure the affected path first, then optimize it on
-  evidence instead of removing it by classification.
 - Arbitrary-precision binary Decimal codecs accept only scales in
   `[-10_000, 10_000]` and an absolute unscaled magnitude of at most `10_000`
   binary bytes. The Java standalone `BigInteger` serializer uses the same
@@ -226,6 +202,10 @@ This is the entry point for AI guidance in Apache Fory. 
Read this file first, th
 - Do not make design tradeoffs the user did not request. If a refactor appears 
to require a behavior, logic, protocol, or performance tradeoff, stop and ask.
 - Treat existing low-level or optimized code as deliberate by default. During 
a refactor, preserve the current implementation strategy unless the user 
explicitly asks to redesign or optimize it.
 - Do not replace existing C, C++, Cython, unsafe, or other low-level optimized 
paths with simpler high-level implementations just to make a refactor easier.
+- When removing a redundant wrapper or helper, preserve any aggregate capacity 
proof, fused
+  operation, reserved wide store, specialized overload, or unchecked primitive 
path in the natural
+  owner. Do not route that work through a generic checked path unless matched 
benchmarks justify the
+  implementation change.
 - If a refactor accidentally changes logic or implementation strategy, revert 
that part and re-implement the refactor around the existing logic.
 - Use English only in code, comments, and documentation.
 - Do not use emoji in documentation, including headings, feature lists, status
diff --git a/cpp/fory/serialization/array_serializer.h 
b/cpp/fory/serialization/array_serializer.h
index 25580f18a..49d31456d 100644
--- a/cpp/fory/serialization/array_serializer.h
+++ b/cpp/fory/serialization/array_serializer.h
@@ -93,8 +93,8 @@ struct Serializer<
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
     // write array length in bytes
-    writer_index += buffer.put_var_uint32(writer_index,
-                                          static_cast<uint32_t>(N * 
sizeof(T)));
+    writer_index += buffer.put_var_uint32_unchecked(
+        writer_index, static_cast<uint32_t>(N * sizeof(T)));
 
     // write data
     if constexpr (N > 0) {
@@ -110,7 +110,7 @@ struct Serializer<
         }
       }
     }
-    buffer.writer_index(writer_index + N * sizeof(T));
+    buffer.unsafe_set_writer_index(writer_index + N * sizeof(T));
   }
 
   static inline void write_data_generic(const std::array<T, N> &arr,
@@ -221,14 +221,14 @@ template <size_t N> struct Serializer<std::array<bool, 
N>> {
     uint32_t writer_index = buffer.writer_index();
     // write array length
     writer_index +=
-        buffer.put_var_uint32(writer_index, static_cast<uint32_t>(N));
+        buffer.put_var_uint32_unchecked(writer_index, 
static_cast<uint32_t>(N));
 
     // write each boolean as a byte
     for (size_t i = 0; i < N; ++i) {
       buffer.unsafe_put_byte(writer_index + i,
                              static_cast<uint8_t>(arr[i] ? 1 : 0));
     }
-    buffer.writer_index(writer_index + N);
+    buffer.unsafe_set_writer_index(writer_index + N);
   }
 
   static inline void write_data_generic(const std::array<bool, N> &arr,
@@ -323,7 +323,7 @@ template <size_t N> struct Serializer<std::array<float16_t, 
N>> {
     constexpr size_t max_size = 8 + N * sizeof(float16_t);
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
-    writer_index += buffer.put_var_uint32(
+    writer_index += buffer.put_var_uint32_unchecked(
         writer_index, static_cast<uint32_t>(N * sizeof(float16_t)));
     if constexpr (N > 0) {
       if constexpr (FORY_LITTLE_ENDIAN) {
@@ -336,7 +336,7 @@ template <size_t N> struct Serializer<std::array<float16_t, 
N>> {
         }
       }
     }
-    buffer.writer_index(writer_index + N * sizeof(float16_t));
+    buffer.unsafe_set_writer_index(writer_index + N * sizeof(float16_t));
   }
 
   static inline void write_data_generic(const std::array<float16_t, N> &arr,
@@ -436,7 +436,7 @@ template <size_t N> struct 
Serializer<std::array<bfloat16_t, N>> {
     constexpr size_t max_size = 8 + N * sizeof(bfloat16_t);
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
-    writer_index += buffer.put_var_uint32(
+    writer_index += buffer.put_var_uint32_unchecked(
         writer_index, static_cast<uint32_t>(N * sizeof(bfloat16_t)));
     if constexpr (N > 0) {
       if constexpr (FORY_LITTLE_ENDIAN) {
@@ -449,7 +449,7 @@ template <size_t N> struct 
Serializer<std::array<bfloat16_t, N>> {
         }
       }
     }
-    buffer.writer_index(writer_index + N * sizeof(bfloat16_t));
+    buffer.unsafe_set_writer_index(writer_index + N * sizeof(bfloat16_t));
   }
 
   static inline void write_data_generic(const std::array<bfloat16_t, N> &arr,
diff --git a/cpp/fory/serialization/collection_serializer.h 
b/cpp/fory/serialization/collection_serializer.h
index 905f0fa29..bafe03a46 100644
--- a/cpp/fory/serialization/collection_serializer.h
+++ b/cpp/fory/serialization/collection_serializer.h
@@ -50,36 +50,21 @@ constexpr uint8_t COLL_IS_SAME_TYPE = 0b1000;
 
 namespace detail {
 
-/// Primitive vectors reserve their header and complete body before writing.
-/// Commit that proven range directly so public random-access safety checks do
-/// not expand every generated vector-field write.
-struct PrimitiveVectorWriter {
-  FORY_ALWAYS_INLINE static bool reserve(WriteContext &ctx,
-                                         uint64_t body_size) {
-    Buffer &buffer = ctx.buffer();
-    const uint64_t required_size =
-        static_cast<uint64_t>(buffer.writer_index()) + 8 + body_size;
-    if (FORY_PREDICT_FALSE(required_size >=
-                           std::numeric_limits<uint32_t>::max())) {
-      ctx.set_error(
-          Error::invalid("Vector write exceeds uint32_t buffer range"));
-      return false;
-    }
-    // The uint32 encoder may make an eight-byte physical store for a five-byte
-    // value. Reserve that physical extent together with the complete body.
-    buffer.grow(static_cast<uint32_t>(8 + body_size));
-    return true;
-  }
-
-  FORY_ALWAYS_INLINE static uint32_t put_size(Buffer &buffer, uint32_t offset,
-                                              uint32_t size) {
-    return buffer.put_var_uint32_unchecked(offset, size);
-  }
-
-  FORY_ALWAYS_INLINE static void commit(Buffer &buffer, uint32_t offset) {
-    buffer.writer_index_ = offset;
+FORY_ALWAYS_INLINE bool reserve_primitive_vector(WriteContext &ctx,
+                                                 uint64_t body_size) {
+  Buffer &buffer = ctx.buffer();
+  const uint64_t required_size =
+      static_cast<uint64_t>(buffer.writer_index()) + 8 + body_size;
+  if (FORY_PREDICT_FALSE(required_size >=
+                         std::numeric_limits<uint32_t>::max())) {
+    ctx.set_error(Error::invalid("Vector write exceeds uint32_t buffer 
range"));
+    return false;
   }
-};
+  // The uint32 encoder may make an eight-byte physical store for a five-byte
+  // value. Reserve that physical extent together with the complete body.
+  buffer.grow(static_cast<uint32_t>(8 + body_size));
+  return true;
+}
 
 } // namespace detail
 
@@ -1019,19 +1004,19 @@ struct Serializer<
   static inline void write_data(const std::vector<T, Alloc> &vec,
                                 WriteContext &ctx) {
     uint64_t total_bytes = static_cast<uint64_t>(vec.size()) * sizeof(T);
-    if (!detail::PrimitiveVectorWriter::reserve(ctx, total_bytes)) {
+    if (!detail::reserve_primitive_vector(ctx, total_bytes)) {
       return;
     }
     Buffer &buffer = ctx.buffer();
     uint32_t writer_index = buffer.writer_index();
-    writer_index += detail::PrimitiveVectorWriter::put_size(
-        buffer, writer_index, static_cast<uint32_t>(total_bytes));
+    writer_index += buffer.put_var_uint32_unchecked(
+        writer_index, static_cast<uint32_t>(total_bytes));
     if (total_bytes > 0) {
       buffer.unsafe_put(writer_index, vec.data(),
                         static_cast<uint32_t>(total_bytes));
     }
-    detail::PrimitiveVectorWriter::commit(
-        buffer, writer_index + static_cast<uint32_t>(total_bytes));
+    buffer.unsafe_set_writer_index(writer_index +
+                                   static_cast<uint32_t>(total_bytes));
   }
 
   static inline void write_data_generic(const std::vector<T, Alloc> &vec,
@@ -1132,19 +1117,19 @@ template <typename Alloc> struct 
Serializer<std::vector<float16_t, Alloc>> {
                                 WriteContext &ctx) {
     uint64_t total_bytes =
         static_cast<uint64_t>(vec.size()) * sizeof(float16_t);
-    if (!detail::PrimitiveVectorWriter::reserve(ctx, total_bytes)) {
+    if (!detail::reserve_primitive_vector(ctx, total_bytes)) {
       return;
     }
     Buffer &buffer = ctx.buffer();
     uint32_t writer_index = buffer.writer_index();
-    writer_index += detail::PrimitiveVectorWriter::put_size(
-        buffer, writer_index, static_cast<uint32_t>(total_bytes));
+    writer_index += buffer.put_var_uint32_unchecked(
+        writer_index, static_cast<uint32_t>(total_bytes));
     if (total_bytes > 0) {
       buffer.unsafe_put(writer_index, vec.data(),
                         static_cast<uint32_t>(total_bytes));
     }
-    detail::PrimitiveVectorWriter::commit(
-        buffer, writer_index + static_cast<uint32_t>(total_bytes));
+    buffer.unsafe_set_writer_index(writer_index +
+                                   static_cast<uint32_t>(total_bytes));
   }
 
   static inline void
@@ -1237,19 +1222,19 @@ template <typename Alloc> struct 
Serializer<std::vector<bfloat16_t, Alloc>> {
                                 WriteContext &ctx) {
     uint64_t total_bytes =
         static_cast<uint64_t>(vec.size()) * sizeof(bfloat16_t);
-    if (!detail::PrimitiveVectorWriter::reserve(ctx, total_bytes)) {
+    if (!detail::reserve_primitive_vector(ctx, total_bytes)) {
       return;
     }
     Buffer &buffer = ctx.buffer();
     uint32_t writer_index = buffer.writer_index();
-    writer_index += detail::PrimitiveVectorWriter::put_size(
-        buffer, writer_index, static_cast<uint32_t>(total_bytes));
+    writer_index += buffer.put_var_uint32_unchecked(
+        writer_index, static_cast<uint32_t>(total_bytes));
     if (total_bytes > 0) {
       buffer.unsafe_put(writer_index, vec.data(),
                         static_cast<uint32_t>(total_bytes));
     }
-    detail::PrimitiveVectorWriter::commit(
-        buffer, writer_index + static_cast<uint32_t>(total_bytes));
+    buffer.unsafe_set_writer_index(writer_index +
+                                   static_cast<uint32_t>(total_bytes));
   }
 
   static inline void
@@ -1530,20 +1515,20 @@ template <typename Alloc> struct 
Serializer<std::vector<bool, Alloc>> {
 
   static inline void write_data(const std::vector<bool, Alloc> &vec,
                                 WriteContext &ctx) {
-    if (!detail::PrimitiveVectorWriter::reserve(
-            ctx, static_cast<uint64_t>(vec.size()))) {
+    if (!detail::reserve_primitive_vector(ctx,
+                                          static_cast<uint64_t>(vec.size()))) {
       return;
     }
     Buffer &buffer = ctx.buffer();
     uint32_t writer_index = buffer.writer_index();
-    writer_index += detail::PrimitiveVectorWriter::put_size(
-        buffer, writer_index, static_cast<uint32_t>(vec.size()));
+    writer_index += buffer.put_var_uint32_unchecked(
+        writer_index, static_cast<uint32_t>(vec.size()));
     for (size_t i = 0; i < vec.size(); ++i) {
       buffer.unsafe_put_byte(writer_index + i,
                              static_cast<uint8_t>(vec[i] ? 1 : 0));
     }
-    detail::PrimitiveVectorWriter::commit(
-        buffer, writer_index + static_cast<uint32_t>(vec.size()));
+    buffer.unsafe_set_writer_index(writer_index +
+                                   static_cast<uint32_t>(vec.size()));
   }
 
   static inline void write_data_generic(const std::vector<bool, Alloc> &vec,
diff --git a/cpp/fory/serialization/serialization_test.cc 
b/cpp/fory/serialization/serialization_test.cc
index 95ee19228..e7ea4989a 100644
--- a/cpp/fory/serialization/serialization_test.cc
+++ b/cpp/fory/serialization/serialization_test.cc
@@ -433,7 +433,7 @@ TEST(SerializationTest, 
PrimitiveVectorWriteChecksCompleteRange) {
       Fory::builder().xlang(true).compatible(false).track_ref(false).build();
   WriteContext write_ctx(fory.config(), fory.type_resolver().clone());
 
-  EXPECT_FALSE(detail::PrimitiveVectorWriter::reserve(
+  EXPECT_FALSE(detail::reserve_primitive_vector(
       write_ctx, std::numeric_limits<uint32_t>::max()));
   EXPECT_TRUE(write_ctx.has_error());
   EXPECT_EQ(write_ctx.buffer().writer_index(), 0U);
diff --git a/cpp/fory/serialization/string_serializer.h 
b/cpp/fory/serialization/string_serializer.h
index 45a617483..21ea09943 100644
--- a/cpp/fory/serialization/string_serializer.h
+++ b/cpp/fory/serialization/string_serializer.h
@@ -47,20 +47,6 @@ enum class StringEncoding : uint8_t {
 
 namespace detail {
 
-struct StringFieldWriter {
-  FORY_ALWAYS_INLINE static uint32_t put_size(Buffer &buffer, uint32_t offset,
-                                              uint64_t size) {
-    return buffer.put_var_uint64_unchecked(offset, size);
-  }
-
-  FORY_ALWAYS_INLINE static void commit(Buffer &buffer, uint32_t offset) {
-    buffer.writer_index_ = offset;
-    if (FORY_PREDICT_FALSE(buffer.output_stream_ != nullptr && offset > 4096)) 
{
-      buffer.output_stream_->try_flush();
-    }
-  }
-};
-
 /// write string data with UTF-8 encoding
 inline void write_string_data(const char *data, size_t size,
                               WriteContext &ctx) {
@@ -79,11 +65,12 @@ inline void write_string_data(const char *data, size_t size,
   buffer.grow(static_cast<uint32_t>(size + 9));
   uint32_t writer_index = buffer.writer_index();
   writer_index +=
-      StringFieldWriter::put_size(buffer, writer_index, size_with_encoding);
+      buffer.put_var_uint64_unchecked(writer_index, size_with_encoding);
   if (size > 0) {
     buffer.unsafe_put(writer_index, data, static_cast<uint32_t>(size));
   }
-  StringFieldWriter::commit(buffer, writer_index + 
static_cast<uint32_t>(size));
+  buffer.unsafe_set_writer_index(writer_index + static_cast<uint32_t>(size));
+  ctx.try_flush();
 }
 
 /// write UTF-16 string data, converting to UTF-8 or using native encoding
diff --git a/cpp/fory/serialization/struct_serializer.h 
b/cpp/fory/serialization/struct_serializer.h
index 4a237305a..d04707935 100644
--- a/cpp/fory/serialization/struct_serializer.h
+++ b/cpp/fory/serialization/struct_serializer.h
@@ -78,35 +78,6 @@ struct SerializationMeta<T,
 
 namespace detail {
 
-/// Generated struct writers reserve the complete primitive-field extent once.
-/// Repeating public offset and cursor checks for each field only expands the
-/// generated hot path; this owner may bypass them after that reservation.
-struct StructFieldWriter {
-  FORY_ALWAYS_INLINE static uint32_t
-  put_var_uint32(Buffer &buffer, uint32_t offset, uint32_t value) {
-    return buffer.put_var_uint32_unchecked(offset, value);
-  }
-
-  FORY_ALWAYS_INLINE static uint32_t
-  put_var_uint64(Buffer &buffer, uint32_t offset, uint64_t value) {
-    return buffer.put_var_uint64_unchecked(offset, value);
-  }
-
-  FORY_ALWAYS_INLINE static uint32_t
-  put_tagged_uint64(Buffer &buffer, uint32_t offset, uint64_t value) {
-    return buffer.put_tagged_uint64_unchecked(offset, value);
-  }
-
-  FORY_ALWAYS_INLINE static uint32_t
-  put_tagged_int64(Buffer &buffer, uint32_t offset, int64_t value) {
-    return buffer.put_tagged_int64_unchecked(offset, value);
-  }
-
-  FORY_ALWAYS_INLINE static void commit(Buffer &buffer, uint32_t offset) {
-    buffer.writer_index_ = offset;
-  }
-};
-
 /// Helper to check if a TypeId represents a primitive type.
 /// Per xlang spec, primitive types are: bool, int8-64, var_int32/64,
 /// sli_int64, float8/16/bfloat16/32/64. For native mode (xlang=false), also
@@ -202,22 +173,22 @@ FORY_ALWAYS_INLINE uint32_t put_primitive_at(T value, 
Buffer &buffer,
     int32_t val = static_cast<int32_t>(value);
     uint32_t zigzag =
         (static_cast<uint32_t>(val) << 1) ^ static_cast<uint32_t>(val >> 31);
-    return StructFieldWriter::put_var_uint32(buffer, offset, zigzag);
+    return buffer.put_var_uint32_unchecked(offset, zigzag);
   } else if constexpr (std::is_same_v<T, uint32_t> ||
                        std::is_same_v<T, unsigned int>) {
-    return StructFieldWriter::put_var_uint32(buffer, offset,
-                                             static_cast<uint32_t>(value));
+    return buffer.put_var_uint32_unchecked(offset,
+                                           static_cast<uint32_t>(value));
   } else if constexpr (std::is_same_v<T, int64_t> ||
                        std::is_same_v<T, long long>) {
     // varint64 with zigzag encoding
     int64_t val = static_cast<int64_t>(value);
     uint64_t zigzag =
         (static_cast<uint64_t>(val) << 1) ^ static_cast<uint64_t>(val >> 63);
-    return StructFieldWriter::put_var_uint64(buffer, offset, zigzag);
+    return buffer.put_var_uint64_unchecked(offset, zigzag);
   } else if constexpr (std::is_same_v<T, uint64_t> ||
                        std::is_same_v<T, unsigned long long>) {
-    return StructFieldWriter::put_var_uint64(buffer, offset,
-                                             static_cast<uint64_t>(value));
+    return buffer.put_var_uint64_unchecked(offset,
+                                           static_cast<uint64_t>(value));
   } else if constexpr (std::is_same_v<T, int32_t> || std::is_same_v<T, int>) {
     buffer.unsafe_put<int32_t>(offset, static_cast<int32_t>(value));
     return 4;
@@ -301,25 +272,25 @@ FORY_ALWAYS_INLINE uint32_t put_varint_at(T value, Buffer 
&buffer,
     int32_t val = static_cast<int32_t>(value);
     uint32_t zigzag =
         (static_cast<uint32_t>(val) << 1) ^ static_cast<uint32_t>(val >> 31);
-    return StructFieldWriter::put_var_uint32(buffer, offset, zigzag);
+    return buffer.put_var_uint32_unchecked(offset, zigzag);
   } else if constexpr (std::is_same_v<T, int64_t> ||
                        std::is_same_v<T, long long>) {
     // varint64 with zigzag encoding
     int64_t val = static_cast<int64_t>(value);
     uint64_t zigzag =
         (static_cast<uint64_t>(val) << 1) ^ static_cast<uint64_t>(val >> 63);
-    return StructFieldWriter::put_var_uint64(buffer, offset, zigzag);
+    return buffer.put_var_uint64_unchecked(offset, zigzag);
   } else if constexpr (std::is_same_v<T, uint32_t> ||
                        std::is_same_v<T, unsigned int>) {
     // Unsigned 32-bit varint (no zigzag)
-    return StructFieldWriter::put_var_uint32(buffer, offset,
-                                             static_cast<uint32_t>(value));
+    return buffer.put_var_uint32_unchecked(offset,
+                                           static_cast<uint32_t>(value));
   } else if constexpr (std::is_same_v<T, uint64_t> ||
                        std::is_same_v<T, unsigned long long>) {
     // Unsigned 64-bit varint (no zigzag) - used for VAR_UINT64 and
     // TAGGED_UINT64
-    return StructFieldWriter::put_var_uint64(buffer, offset,
-                                             static_cast<uint64_t>(value));
+    return buffer.put_var_uint64_unchecked(offset,
+                                           static_cast<uint64_t>(value));
   } else {
     static_assert(sizeof(T) == 0, "Unsupported varint type");
     return 0;
@@ -461,8 +432,8 @@ FORY_ALWAYS_INLINE uint32_t 
write_configurable_int_at(FieldType value,
       return 8;
     }
     if constexpr (enc == Encoding::Tagged) {
-      return StructFieldWriter::put_tagged_int64(buffer, offset,
-                                                 static_cast<int64_t>(value));
+      return buffer.put_tagged_int64_unchecked(offset,
+                                               static_cast<int64_t>(value));
     }
     return put_varint_at<FieldType>(value, buffer, offset);
   } else {
@@ -476,8 +447,8 @@ FORY_ALWAYS_INLINE uint32_t 
write_configurable_int_at(FieldType value,
     }
     if constexpr (enc == Encoding::Tagged) {
       if constexpr (is_configurable_int64_v<FieldType>) {
-        return StructFieldWriter::put_tagged_uint64(
-            buffer, offset, static_cast<uint64_t>(value));
+        return buffer.put_tagged_uint64_unchecked(offset,
+                                                  
static_cast<uint64_t>(value));
       }
       return put_varint_at<FieldType>(value, buffer, offset);
     }
@@ -2568,8 +2539,8 @@ write_fixed_primitive_fields(const T &obj, Buffer &buffer,
   (write_single_fixed_field<T, Indices>(obj, buffer, base_offset), ...);
 
   // Update writer_index once with total fixed bytes (compile-time constant)
-  StructFieldWriter::commit(buffer,
-                            base_offset + Helpers::leading_fixed_size_bytes);
+  buffer.unsafe_set_writer_index(base_offset +
+                                 Helpers::leading_fixed_size_bytes);
 }
 
 /// Helper to write a single varint primitive field.
@@ -2682,7 +2653,7 @@ write_primitive_fields_fast(const T &obj, Buffer &buffer,
     uint32_t offset = buffer.writer_index();
     write_varint_primitive_fields<T, fixed_count>(
         obj, buffer, offset, std::make_index_sequence<varint_count>{});
-    StructFieldWriter::commit(buffer, offset);
+    buffer.unsafe_set_writer_index(offset);
   }
 
   // Phase 3: write remaining primitives (if any) using dedicated helper
@@ -2692,7 +2663,7 @@ write_primitive_fields_fast(const T &obj, Buffer &buffer,
     write_remaining_primitive_fields<T, fast_count>(
         obj, buffer, offset,
         std::make_index_sequence<total_count - fast_count>{});
-    StructFieldWriter::commit(buffer, offset);
+    buffer.unsafe_set_writer_index(offset);
   }
 }
 
diff --git a/cpp/fory/serialization/unsigned_serializer.h 
b/cpp/fory/serialization/unsigned_serializer.h
index 57c895b71..ac0cb8d17 100644
--- a/cpp/fory/serialization/unsigned_serializer.h
+++ b/cpp/fory/serialization/unsigned_serializer.h
@@ -333,11 +333,11 @@ template <size_t N> struct Serializer<std::array<uint8_t, 
N>> {
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
     writer_index +=
-        buffer.put_var_uint32(writer_index, static_cast<uint32_t>(N));
+        buffer.put_var_uint32_unchecked(writer_index, 
static_cast<uint32_t>(N));
     if constexpr (N > 0) {
       buffer.unsafe_put(writer_index, arr.data(), N * sizeof(uint8_t));
     }
-    buffer.writer_index(writer_index + N * sizeof(uint8_t));
+    buffer.unsafe_set_writer_index(writer_index + N * sizeof(uint8_t));
   }
 
   static inline void write_data_generic(const std::array<uint8_t, N> &arr,
@@ -422,11 +422,11 @@ template <size_t N> struct 
Serializer<std::array<uint16_t, N>> {
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
     writer_index +=
-        buffer.put_var_uint32(writer_index, static_cast<uint32_t>(N));
+        buffer.put_var_uint32_unchecked(writer_index, 
static_cast<uint32_t>(N));
     if constexpr (N > 0) {
       buffer.unsafe_put(writer_index, arr.data(), N * sizeof(uint16_t));
     }
-    buffer.writer_index(writer_index + N * sizeof(uint16_t));
+    buffer.unsafe_set_writer_index(writer_index + N * sizeof(uint16_t));
   }
 
   static inline void write_data_generic(const std::array<uint16_t, N> &arr,
@@ -511,11 +511,11 @@ template <size_t N> struct 
Serializer<std::array<uint32_t, N>> {
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
     writer_index +=
-        buffer.put_var_uint32(writer_index, static_cast<uint32_t>(N));
+        buffer.put_var_uint32_unchecked(writer_index, 
static_cast<uint32_t>(N));
     if constexpr (N > 0) {
       buffer.unsafe_put(writer_index, arr.data(), N * sizeof(uint32_t));
     }
-    buffer.writer_index(writer_index + N * sizeof(uint32_t));
+    buffer.unsafe_set_writer_index(writer_index + N * sizeof(uint32_t));
   }
 
   static inline void write_data_generic(const std::array<uint32_t, N> &arr,
@@ -600,11 +600,11 @@ template <size_t N> struct 
Serializer<std::array<uint64_t, N>> {
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
     writer_index +=
-        buffer.put_var_uint32(writer_index, static_cast<uint32_t>(N));
+        buffer.put_var_uint32_unchecked(writer_index, 
static_cast<uint32_t>(N));
     if constexpr (N > 0) {
       buffer.unsafe_put(writer_index, arr.data(), N * sizeof(uint64_t));
     }
-    buffer.writer_index(writer_index + N * sizeof(uint64_t));
+    buffer.unsafe_set_writer_index(writer_index + N * sizeof(uint64_t));
   }
 
   static inline void write_data_generic(const std::array<uint64_t, N> &arr,
@@ -693,12 +693,13 @@ template <> struct Serializer<std::vector<uint8_t>> {
     size_t max_size = 8 + vec.size();
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
-    writer_index +=
-        buffer.put_var_uint32(writer_index, static_cast<uint32_t>(vec.size()));
+    writer_index += buffer.put_var_uint32_unchecked(
+        writer_index, static_cast<uint32_t>(vec.size()));
     if (!vec.empty()) {
       buffer.unsafe_put(writer_index, vec.data(), vec.size());
     }
-    buffer.writer_index(writer_index + static_cast<uint32_t>(vec.size()));
+    buffer.unsafe_set_writer_index(writer_index +
+                                   static_cast<uint32_t>(vec.size()));
   }
 
   static inline void write_data_generic(const std::vector<uint8_t> &vec,
@@ -786,13 +787,14 @@ template <> struct Serializer<std::vector<uint16_t>> {
     size_t max_size = 8 + static_cast<size_t>(total_bytes);
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
-    writer_index +=
-        buffer.put_var_uint32(writer_index, 
static_cast<uint32_t>(total_bytes));
+    writer_index += buffer.put_var_uint32_unchecked(
+        writer_index, static_cast<uint32_t>(total_bytes));
     if (total_bytes > 0) {
       buffer.unsafe_put(writer_index, vec.data(),
                         static_cast<uint32_t>(total_bytes));
     }
-    buffer.writer_index(writer_index + static_cast<uint32_t>(total_bytes));
+    buffer.unsafe_set_writer_index(writer_index +
+                                   static_cast<uint32_t>(total_bytes));
   }
 
   static inline void write_data_generic(const std::vector<uint16_t> &vec,
@@ -891,13 +893,14 @@ template <> struct Serializer<std::vector<uint32_t>> {
     size_t max_size = 8 + static_cast<size_t>(total_bytes);
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
-    writer_index +=
-        buffer.put_var_uint32(writer_index, 
static_cast<uint32_t>(total_bytes));
+    writer_index += buffer.put_var_uint32_unchecked(
+        writer_index, static_cast<uint32_t>(total_bytes));
     if (total_bytes > 0) {
       buffer.unsafe_put(writer_index, vec.data(),
                         static_cast<uint32_t>(total_bytes));
     }
-    buffer.writer_index(writer_index + static_cast<uint32_t>(total_bytes));
+    buffer.unsafe_set_writer_index(writer_index +
+                                   static_cast<uint32_t>(total_bytes));
   }
 
   static inline void write_data_generic(const std::vector<uint32_t> &vec,
@@ -996,13 +999,14 @@ template <> struct Serializer<std::vector<uint64_t>> {
     size_t max_size = 8 + static_cast<size_t>(total_bytes);
     buffer.grow(static_cast<uint32_t>(max_size));
     uint32_t writer_index = buffer.writer_index();
-    writer_index +=
-        buffer.put_var_uint32(writer_index, 
static_cast<uint32_t>(total_bytes));
+    writer_index += buffer.put_var_uint32_unchecked(
+        writer_index, static_cast<uint32_t>(total_bytes));
     if (total_bytes > 0) {
       buffer.unsafe_put(writer_index, vec.data(),
                         static_cast<uint32_t>(total_bytes));
     }
-    buffer.writer_index(writer_index + static_cast<uint32_t>(total_bytes));
+    buffer.unsafe_set_writer_index(writer_index +
+                                   static_cast<uint32_t>(total_bytes));
   }
 
   static inline void write_data_generic(const std::vector<uint64_t> &vec,
diff --git a/cpp/fory/util/buffer.h b/cpp/fory/util/buffer.h
index 69ecc256f..76a9cea8b 100644
--- a/cpp/fory/util/buffer.h
+++ b/cpp/fory/util/buffer.h
@@ -39,11 +39,6 @@ namespace fory {
 
 class StdInputStream;
 class PyInputStream;
-namespace serialization::detail {
-struct PrimitiveVectorWriter;
-struct StructFieldWriter;
-struct StringFieldWriter;
-} // namespace serialization::detail
 
 // A buffer class for storing raw bytes with various methods for reading and
 // writing the bytes.
@@ -235,11 +230,16 @@ public:
     reader_index_ += diff;
   }
 
-  // Unsafe methods don't check bound
+  // Unsafe operations trust callers to prove the complete physical extent or
+  // cursor position.
   FORY_ALWAYS_INLINE void unsafe_increase_reader_index(uint32_t diff) {
     reader_index_ += diff;
   }
 
+  FORY_ALWAYS_INLINE void unsafe_set_writer_index(uint32_t writer_index) {
+    writer_index_ = writer_index;
+  }
+
   template <typename T>
   FORY_ALWAYS_INLINE void unsafe_put(uint32_t offset, T value) {
     store_unaligned(data_ + offset, value);
@@ -361,18 +361,116 @@ public:
     return Result<void, Error>();
   }
 
-  /// Put unsigned varint32 at offset using optimized bulk writes.
-  /// Returns number of bytes written (1-5).
-  /// Uses bit manipulation to build encoded value, then single memory write.
-  FORY_ALWAYS_INLINE uint32_t put_var_uint32(uint32_t offset, uint32_t value) {
-    const uint32_t extent = value < 0x80         ? 1
-                            : value < 0x4000     ? 2
-                            : value < 0x10000000 ? 4
-                                                 : 8;
-    if (FORY_PREDICT_FALSE(!range_in_bounds(offset, extent))) {
-      fail_range(offset, extent);
+  /// Put unsigned varint32 at an unchecked offset using optimized bulk writes.
+  /// The caller must reserve the complete physical store extent, which can be
+  /// larger than the returned logical byte count.
+  FORY_ALWAYS_INLINE uint32_t put_var_uint32_unchecked(uint32_t offset,
+                                                       uint32_t value) {
+    if (value < 0x80) {
+      data_[offset] = static_cast<uint8_t>(value);
+      return 1;
+    }
+    // Bulk stores keep the hot path branch-light. Callers must establish the
+    // physical extent selected below, which may exceed the logical encoding.
+    uint64_t encoded = (value & 0x7F) | 0x80;
+    encoded |= (static_cast<uint64_t>(value & 0x3F80) << 1);
+    if (value < 0x4000) {
+      store_unaligned<uint16_t>(data_ + offset, 
static_cast<uint16_t>(encoded));
+      return 2;
+    }
+    encoded |= (static_cast<uint64_t>(value & 0x1FC000) << 2) | 0x8000;
+    if (value < 0x200000) {
+      store_unaligned<uint32_t>(data_ + offset, 
static_cast<uint32_t>(encoded));
+      return 3;
+    }
+    encoded |= (static_cast<uint64_t>(value & 0xFE00000) << 3) | 0x800000;
+    if (value < 0x10000000) {
+      store_unaligned<uint32_t>(data_ + offset, 
static_cast<uint32_t>(encoded));
+      return 4;
+    }
+    encoded |= (static_cast<uint64_t>(value >> 28) << 32) | 0x80000000;
+    store_unaligned<uint64_t>(data_ + offset, encoded);
+    return 5;
+  }
+
+  /// Put unsigned varint64 at an unchecked offset using PVL encoding.
+  /// The caller must reserve the complete physical store extent.
+  FORY_ALWAYS_INLINE uint32_t put_var_uint64_unchecked(uint32_t offset,
+                                                       uint64_t value) {
+    if (value < 0x80) {
+      data_[offset] = static_cast<uint8_t>(value);
+      return 1;
+    }
+    uint64_t encoded = (value & 0x7F) | 0x80;
+    encoded |= ((value & 0x3F80) << 1);
+    if (value < 0x4000) {
+      store_unaligned<uint16_t>(data_ + offset, 
static_cast<uint16_t>(encoded));
+      return 2;
+    }
+    encoded |= ((value & 0x1FC000) << 2) | 0x8000;
+    if (value < 0x200000) {
+      store_unaligned<uint32_t>(data_ + offset, 
static_cast<uint32_t>(encoded));
+      return 3;
+    }
+    encoded |= ((value & 0xFE00000) << 3) | 0x800000;
+    if (value < 0x10000000) {
+      store_unaligned<uint32_t>(data_ + offset, 
static_cast<uint32_t>(encoded));
+      return 4;
+    }
+    encoded |= ((value & 0x7F0000000ULL) << 4) | 0x80000000;
+    if (value < 0x800000000ULL) {
+      store_unaligned<uint64_t>(data_ + offset, encoded);
+      return 5;
+    }
+    encoded |= ((value & 0x3F800000000ULL) << 5) | 0x8000000000ULL;
+    if (value < 0x40000000000ULL) {
+      store_unaligned<uint64_t>(data_ + offset, encoded);
+      return 6;
+    }
+    encoded |= ((value & 0x1FC0000000000ULL) << 6) | 0x800000000000ULL;
+    if (value < 0x2000000000000ULL) {
+      store_unaligned<uint64_t>(data_ + offset, encoded);
+      return 7;
+    }
+    encoded |= ((value & 0xFE000000000000ULL) << 7) | 0x80000000000000ULL;
+    if (value < 0x100000000000000ULL) {
+      store_unaligned<uint64_t>(data_ + offset, encoded);
+      return 8;
+    }
+    encoded |= 0x8000000000000000ULL;
+    store_unaligned<uint64_t>(data_ + offset, encoded);
+    data_[offset + 8] = static_cast<uint8_t>(value >> 56);
+    return 9;
+  }
+
+  /// Put a tagged uint64 at an unchecked offset. Returns 4 or 9 bytes.
+  FORY_ALWAYS_INLINE uint32_t put_tagged_uint64_unchecked(uint32_t offset,
+                                                          uint64_t value) {
+    constexpr uint64_t MAX_SMALL_VALUE = 0x7fffffff;
+    if (value <= MAX_SMALL_VALUE) {
+      store_unaligned<uint32_t>(data_ + offset, static_cast<uint32_t>(value)
+                                                    << 1);
+      return 4;
+    }
+    data_[offset] = 0b1;
+    store_unaligned<uint64_t>(data_ + offset + 1, value);
+    return 9;
+  }
+
+  /// Put a tagged int64 at an unchecked offset. Returns 4 or 9 bytes.
+  FORY_ALWAYS_INLINE uint32_t put_tagged_int64_unchecked(uint32_t offset,
+                                                         int64_t value) {
+    constexpr int64_t MIN_SMALL_VALUE = -1073741824;
+    constexpr int64_t MAX_SMALL_VALUE = 1073741823;
+    if (value >= MIN_SMALL_VALUE && value <= MAX_SMALL_VALUE) {
+      const uint32_t encoded =
+          static_cast<uint32_t>(static_cast<int32_t>(value)) << 1;
+      store_unaligned<uint32_t>(data_ + offset, encoded);
+      return 4;
     }
-    return put_var_uint32_unchecked(offset, value);
+    data_[offset] = 0b1;
+    store_unaligned<int64_t>(data_ + offset + 1, value);
+    return 9;
   }
 
   /// get unsigned varint32 from offset using optimized bulk read.
@@ -467,21 +565,6 @@ public:
     return result;
   }
 
-  /// Put unsigned varint64 at offset using optimized bulk writes.
-  /// Returns number of bytes written (1-9).
-  /// Uses PVL (Progressive Variable-length Long) encoding per xlang spec.
-  FORY_ALWAYS_INLINE uint32_t put_var_uint64(uint32_t offset, uint64_t value) {
-    const uint32_t extent = value < 0x80                   ? 1
-                            : value < 0x4000               ? 2
-                            : value < 0x10000000           ? 4
-                            : value < 0x100000000000000ULL ? 8
-                                                           : 9;
-    if (FORY_PREDICT_FALSE(!range_in_bounds(offset, extent))) {
-      fail_range(offset, extent);
-    }
-    return put_var_uint64_unchecked(offset, value);
-  }
-
   /// get unsigned varint64 from offset using optimized bulk read.
   /// Fast path: bulk read 8 bytes + bit extraction when enough bytes 
available.
   /// Slow path: byte-by-byte for buffer edge cases.
@@ -621,42 +704,12 @@ public:
     }
   }
 
-  /// write uint64_t using tagged encoding at given offset. Returns bytes
-  /// written.
-  /// - If value is in [0, 0x7fffffff]: write 4 bytes (value << 1), return 4
-  /// - Otherwise: write 1 byte flag + 8 bytes uint64, return 9
-  FORY_ALWAYS_INLINE uint32_t put_tagged_uint64(uint32_t offset,
-                                                uint64_t value) {
-    constexpr uint64_t MAX_SMALL_VALUE = 0x7fffffff; // INT32_MAX as u64
-    const uint32_t extent = value <= MAX_SMALL_VALUE ? 4 : 9;
-    if (FORY_PREDICT_FALSE(!range_in_bounds(offset, extent))) {
-      fail_range(offset, extent);
-    }
-    return put_tagged_uint64_unchecked(offset, value);
-  }
-
-  /// write int64_t using tagged encoding at given offset. Returns bytes
-  /// written.
-  /// - If value is in [-1073741824, 1073741823]: write 4 bytes (value << 1),
-  /// return 4
-  /// - Otherwise: write 1 byte flag + 8 bytes int64, return 9
-  FORY_ALWAYS_INLINE uint32_t put_tagged_int64(uint32_t offset, int64_t value) 
{
-    constexpr int64_t MIN_SMALL_VALUE = -1073741824; // -2^30
-    constexpr int64_t MAX_SMALL_VALUE = 1073741823;  // 2^30 - 1
-    const uint32_t extent =
-        value >= MIN_SMALL_VALUE && value <= MAX_SMALL_VALUE ? 4 : 9;
-    if (FORY_PREDICT_FALSE(!range_in_bounds(offset, extent))) {
-      fail_range(offset, extent);
-    }
-    return put_tagged_int64_unchecked(offset, value);
-  }
-
   /// write uint8_t value to buffer at current writer index.
   /// Automatically grows buffer and advances writer index.
   FORY_ALWAYS_INLINE void write_uint8(uint8_t value) {
     grow(1);
     unsafe_put_byte(writer_index_, value);
-    advance_writer_index_unchecked(1);
+    writer_index_ += 1;
   }
 
   /// write int8_t value to buffer at current writer index.
@@ -664,7 +717,7 @@ public:
   FORY_ALWAYS_INLINE void write_int8(int8_t value) {
     grow(1);
     unsafe_put_byte(writer_index_, static_cast<uint8_t>(value));
-    advance_writer_index_unchecked(1);
+    writer_index_ += 1;
   }
 
   /// write uint16_t value as fixed 2 bytes to buffer at current writer index.
@@ -672,7 +725,7 @@ public:
   FORY_ALWAYS_INLINE void write_uint16(uint16_t value) {
     grow(2);
     unsafe_put<uint16_t>(writer_index_, value);
-    advance_writer_index_unchecked(2);
+    writer_index_ += 2;
   }
 
   /// write int16_t value as fixed 2 bytes to buffer at current writer index.
@@ -680,7 +733,7 @@ public:
   FORY_ALWAYS_INLINE void write_int16(int16_t value) {
     grow(2);
     unsafe_put<int16_t>(writer_index_, value);
-    advance_writer_index_unchecked(2);
+    writer_index_ += 2;
   }
 
   /// write int24 value as fixed 3 bytes to buffer at current writer index.
@@ -688,7 +741,7 @@ public:
   FORY_ALWAYS_INLINE void write_int24(int32_t value) {
     grow(3);
     put_int24(writer_index_, value);
-    advance_writer_index_unchecked(3);
+    writer_index_ += 3;
   }
 
   /// write int32_t value as fixed 4 bytes to buffer at current writer index.
@@ -696,7 +749,7 @@ public:
   FORY_ALWAYS_INLINE void write_int32(int32_t value) {
     grow(4);
     unsafe_put<int32_t>(writer_index_, value);
-    advance_writer_index_unchecked(4);
+    writer_index_ += 4;
   }
 
   /// write uint32_t value as fixed 4 bytes to buffer at current writer index.
@@ -704,7 +757,7 @@ public:
   FORY_ALWAYS_INLINE void write_uint32(uint32_t value) {
     grow(4);
     unsafe_put<uint32_t>(writer_index_, value);
-    advance_writer_index_unchecked(4);
+    writer_index_ += 4;
   }
 
   /// write int64_t value as fixed 8 bytes to buffer at current writer index.
@@ -712,7 +765,7 @@ public:
   FORY_ALWAYS_INLINE void write_int64(int64_t value) {
     grow(8);
     unsafe_put<int64_t>(writer_index_, value);
-    advance_writer_index_unchecked(8);
+    writer_index_ += 8;
   }
 
   /// write float value as fixed 4 bytes to buffer at current writer index.
@@ -720,7 +773,7 @@ public:
   FORY_ALWAYS_INLINE void write_float(float value) {
     grow(4);
     unsafe_put<float>(writer_index_, value);
-    advance_writer_index_unchecked(4);
+    writer_index_ += 4;
   }
 
   /// write double value as fixed 8 bytes to buffer at current writer index.
@@ -728,7 +781,7 @@ public:
   FORY_ALWAYS_INLINE void write_double(double value) {
     grow(8);
     unsafe_put<double>(writer_index_, value);
-    advance_writer_index_unchecked(8);
+    writer_index_ += 8;
   }
 
   /// Write float16_t as fixed 2 bytes (raw IEEE 754 bits, little-endian).
@@ -736,7 +789,7 @@ public:
   FORY_ALWAYS_INLINE void write_f16(float16_t value) {
     grow(2);
     unsafe_put<uint16_t>(writer_index_, value.to_bits());
-    advance_writer_index_unchecked(2);
+    writer_index_ += 2;
   }
 
   /// Write bfloat16_t as fixed 2 bytes (raw IEEE 754 bits, little-endian).
@@ -744,7 +797,7 @@ public:
   FORY_ALWAYS_INLINE void write_bf16(bfloat16_t value) {
     grow(2);
     unsafe_put<uint16_t>(writer_index_, value.to_bits());
-    advance_writer_index_unchecked(2);
+    writer_index_ += 2;
   }
 
   /// write uint32_t value as varint to buffer at current writer index.
@@ -752,7 +805,7 @@ public:
   FORY_ALWAYS_INLINE void write_var_uint32(uint32_t value) {
     grow(8); // bulk write may write 8 bytes for varint32
     uint32_t len = put_var_uint32_unchecked(writer_index_, value);
-    advance_writer_index_unchecked(len);
+    writer_index_ += len;
   }
 
   /// write int32_t value as varint (zigzag encoded) to buffer at current
@@ -768,7 +821,7 @@ public:
   FORY_ALWAYS_INLINE void write_var_uint64(uint64_t value) {
     grow(9); // Max 9 bytes for varint64
     uint32_t len = put_var_uint64_unchecked(writer_index_, value);
-    advance_writer_index_unchecked(len);
+    writer_index_ += len;
   }
 
   /// write int64_t value as varint (zigzag encoded) to buffer at current
@@ -794,7 +847,7 @@ public:
   FORY_ALWAYS_INLINE void write_bytes(const void *data, uint32_t length) {
     grow(length);
     unsafe_put(writer_index_, data, length);
-    advance_writer_index_unchecked(length);
+    writer_index_ += length;
     if (FORY_PREDICT_FALSE(output_stream_ != nullptr && writer_index_ > 4096)) 
{
       output_stream_->try_flush();
     }
@@ -1026,7 +1079,7 @@ public:
       grow(9);
       data_[writer_index_] = 0b1;
       unsafe_put<int64_t>(writer_index_ + 1, value);
-      advance_writer_index_unchecked(9);
+      writer_index_ += 9;
     }
   }
 
@@ -1062,7 +1115,7 @@ public:
       grow(9);
       data_[writer_index_] = 0b1;
       unsafe_put<uint64_t>(writer_index_ + 1, value);
-      advance_writer_index_unchecked(9);
+      writer_index_ += 9;
     }
   }
 
@@ -1201,9 +1254,6 @@ public:
   std::string hex() const;
 
 private:
-  friend struct serialization::detail::PrimitiveVectorWriter;
-  friend struct serialization::detail::StructFieldWriter;
-  friend struct serialization::detail::StringFieldWriter;
   friend class StdInputStream;
   friend class PyInputStream;
   friend class OutputStream;
@@ -1300,123 +1350,11 @@ private:
     return result;
   }
 
-  FORY_ALWAYS_INLINE uint32_t put_var_uint32_unchecked(uint32_t offset,
-                                                       uint32_t value) {
-    if (value < 0x80) {
-      data_[offset] = static_cast<uint8_t>(value);
-      return 1;
-    }
-    // Bulk stores keep the hot path branch-light. Callers must establish the
-    // physical extent selected below, which may exceed the logical encoding.
-    uint64_t encoded = (value & 0x7F) | 0x80;
-    encoded |= (static_cast<uint64_t>(value & 0x3F80) << 1);
-    if (value < 0x4000) {
-      store_unaligned<uint16_t>(data_ + offset, 
static_cast<uint16_t>(encoded));
-      return 2;
-    }
-    encoded |= (static_cast<uint64_t>(value & 0x1FC000) << 2) | 0x8000;
-    if (value < 0x200000) {
-      store_unaligned<uint32_t>(data_ + offset, 
static_cast<uint32_t>(encoded));
-      return 3;
-    }
-    encoded |= (static_cast<uint64_t>(value & 0xFE00000) << 3) | 0x800000;
-    if (value < 0x10000000) {
-      store_unaligned<uint32_t>(data_ + offset, 
static_cast<uint32_t>(encoded));
-      return 4;
-    }
-    encoded |= (static_cast<uint64_t>(value >> 28) << 32) | 0x80000000;
-    store_unaligned<uint64_t>(data_ + offset, encoded);
-    return 5;
-  }
-
-  FORY_ALWAYS_INLINE uint32_t put_var_uint64_unchecked(uint32_t offset,
-                                                       uint64_t value) {
-    if (value < 0x80) {
-      data_[offset] = static_cast<uint8_t>(value);
-      return 1;
-    }
-    uint64_t encoded = (value & 0x7F) | 0x80;
-    encoded |= ((value & 0x3F80) << 1);
-    if (value < 0x4000) {
-      store_unaligned<uint16_t>(data_ + offset, 
static_cast<uint16_t>(encoded));
-      return 2;
-    }
-    encoded |= ((value & 0x1FC000) << 2) | 0x8000;
-    if (value < 0x200000) {
-      store_unaligned<uint32_t>(data_ + offset, 
static_cast<uint32_t>(encoded));
-      return 3;
-    }
-    encoded |= ((value & 0xFE00000) << 3) | 0x800000;
-    if (value < 0x10000000) {
-      store_unaligned<uint32_t>(data_ + offset, 
static_cast<uint32_t>(encoded));
-      return 4;
-    }
-    encoded |= ((value & 0x7F0000000ULL) << 4) | 0x80000000;
-    if (value < 0x800000000ULL) {
-      store_unaligned<uint64_t>(data_ + offset, encoded);
-      return 5;
-    }
-    encoded |= ((value & 0x3F800000000ULL) << 5) | 0x8000000000ULL;
-    if (value < 0x40000000000ULL) {
-      store_unaligned<uint64_t>(data_ + offset, encoded);
-      return 6;
-    }
-    encoded |= ((value & 0x1FC0000000000ULL) << 6) | 0x800000000000ULL;
-    if (value < 0x2000000000000ULL) {
-      store_unaligned<uint64_t>(data_ + offset, encoded);
-      return 7;
-    }
-    encoded |= ((value & 0xFE000000000000ULL) << 7) | 0x80000000000000ULL;
-    if (value < 0x100000000000000ULL) {
-      store_unaligned<uint64_t>(data_ + offset, encoded);
-      return 8;
-    }
-    encoded |= 0x8000000000000000ULL;
-    store_unaligned<uint64_t>(data_ + offset, encoded);
-    data_[offset + 8] = static_cast<uint8_t>(value >> 56);
-    return 9;
-  }
-
-  FORY_ALWAYS_INLINE uint32_t put_tagged_uint64_unchecked(uint32_t offset,
-                                                          uint64_t value) {
-    constexpr uint64_t MAX_SMALL_VALUE = 0x7fffffff;
-    if (value <= MAX_SMALL_VALUE) {
-      store_unaligned<uint32_t>(data_ + offset, static_cast<uint32_t>(value)
-                                                    << 1);
-      return 4;
-    }
-    data_[offset] = 0b1;
-    store_unaligned<uint64_t>(data_ + offset + 1, value);
-    return 9;
-  }
-
-  FORY_ALWAYS_INLINE uint32_t put_tagged_int64_unchecked(uint32_t offset,
-                                                         int64_t value) {
-    constexpr int64_t MIN_SMALL_VALUE = -1073741824;
-    constexpr int64_t MAX_SMALL_VALUE = 1073741823;
-    if (value >= MIN_SMALL_VALUE && value <= MAX_SMALL_VALUE) {
-      const uint32_t encoded =
-          static_cast<uint32_t>(static_cast<int32_t>(value)) << 1;
-      store_unaligned<uint32_t>(data_ + offset, encoded);
-      return 4;
-    }
-    data_[offset] = 0b1;
-    store_unaligned<int64_t>(data_ + offset + 1, value);
-    return 9;
-  }
-
   FORY_ALWAYS_INLINE bool range_in_bounds(uint32_t offset,
                                           uint32_t length) const {
     return offset <= size_ && length <= size_ - offset;
   }
 
-  // Auto-growing writers call this only after grow() has proved the complete
-  // physical store extent and the uint32 writer-index range. Rechecking here
-  // would make every scalar write pay twice for the same safety proof.
-  FORY_ALWAYS_INLINE void advance_writer_index_unchecked(uint32_t diff) {
-    writer_index_ += diff;
-  }
-
   FORY_ALWAYS_INLINE void grow_to_fit(uint32_t required_size) {
     constexpr uint64_t kMaxBufferSize = std::numeric_limits<uint32_t>::max();
     if (required_size <= size_) {
diff --git a/cpp/fory/util/buffer_test.cc b/cpp/fory/util/buffer_test.cc
index d8996a195..3fb033f35 100644
--- a/cpp/fory/util/buffer_test.cc
+++ b/cpp/fory/util/buffer_test.cc
@@ -122,7 +122,8 @@ TEST(Buffer, to_string) {
 
 void check_var_uint32(int32_t start_offset, std::shared_ptr<Buffer> buffer,
                       int32_t value, uint32_t bytes_written) {
-  uint32_t actual_bytes_written = buffer->put_var_uint32(start_offset, value);
+  uint32_t actual_bytes_written =
+      buffer->put_var_uint32_unchecked(start_offset, value);
   EXPECT_EQ(actual_bytes_written, bytes_written);
   uint32_t read_bytes_length;
   int32_t var_int = buffer->get_var_uint32(start_offset, &read_bytes_length);
@@ -149,7 +150,8 @@ TEST(Buffer, TestVarUint) {
 
 void check_var_uint64(int32_t start_offset, std::shared_ptr<Buffer> buffer,
                       uint64_t value, uint32_t bytes_written) {
-  uint32_t actual_bytes_written = buffer->put_var_uint64(start_offset, value);
+  uint32_t actual_bytes_written =
+      buffer->put_var_uint64_unchecked(start_offset, value);
   EXPECT_EQ(actual_bytes_written, bytes_written);
   uint32_t read_bytes_length;
   uint64_t var_int = buffer->get_var_uint64(start_offset, &read_bytes_length);
@@ -305,11 +307,6 @@ TEST(Buffer, OffsetRangeRejectsOverflow) {
                "");
   buffer->unsafe_put<uint32_t>(0, 1);
   EXPECT_DEATH(buffer->get_tagged_int64(0, &bytes_read), "");
-  EXPECT_DEATH(
-      buffer->put_tagged_uint64(std::numeric_limits<uint32_t>::max(), 0), "");
-  EXPECT_DEATH(buffer->put_tagged_int64(0, 
std::numeric_limits<int64_t>::max()),
-               "");
-
   const uint8_t byte = 1;
   EXPECT_DEATH(
       buffer->copy_from(std::numeric_limits<uint32_t>::max(), &byte, 0, 1), 
"");
@@ -347,44 +344,6 @@ TEST(Buffer, RepresentedCopySupportsOverlap) {
   EXPECT_EQ(bytes, (std::vector<uint8_t>{1, 1, 2, 3, 4}));
 }
 
-TEST(Buffer, VarUintPutChecksPhysicalExtent) {
-  std::shared_ptr<Buffer> one_byte;
-  std::shared_ptr<Buffer> two_bytes;
-  std::shared_ptr<Buffer> three_bytes;
-  std::shared_ptr<Buffer> four_bytes;
-  std::shared_ptr<Buffer> seven_bytes;
-  std::shared_ptr<Buffer> eight_bytes;
-  std::shared_ptr<Buffer> nine_bytes;
-  ASSERT_TRUE(allocate_buffer(1, &one_byte));
-  ASSERT_TRUE(allocate_buffer(2, &two_bytes));
-  ASSERT_TRUE(allocate_buffer(3, &three_bytes));
-  ASSERT_TRUE(allocate_buffer(4, &four_bytes));
-  ASSERT_TRUE(allocate_buffer(7, &seven_bytes));
-  ASSERT_TRUE(allocate_buffer(8, &eight_bytes));
-  ASSERT_TRUE(allocate_buffer(9, &nine_bytes));
-
-  EXPECT_EQ(one_byte->put_var_uint32(0, 0x7f), 1U);
-  EXPECT_EQ(two_bytes->put_var_uint64(0, 0x80), 2U);
-  constexpr uint32_t kThreeByteValue = uint32_t{1} << 14;
-  EXPECT_DEATH(three_bytes->put_var_uint32(0, kThreeByteValue), "");
-  EXPECT_EQ(four_bytes->put_var_uint32(0, kThreeByteValue), 3U);
-  constexpr uint64_t kFourByteValue = uint64_t{1} << 21;
-  EXPECT_EQ(four_bytes->put_var_uint64(0, kFourByteValue), 4U);
-
-  constexpr uint32_t kFiveByteValue = uint32_t{1} << 28;
-  EXPECT_DEATH(seven_bytes->put_var_uint32(0, kFiveByteValue), "");
-  EXPECT_EQ(eight_bytes->put_var_uint32(0, kFiveByteValue), 5U);
-  uint32_t bytes_read = 0;
-  EXPECT_EQ(eight_bytes->get_var_uint32(0, &bytes_read), kFiveByteValue);
-  EXPECT_EQ(bytes_read, 5U);
-
-  constexpr uint64_t kNineByteValue = uint64_t{1} << 56;
-  EXPECT_DEATH(eight_bytes->put_var_uint64(0, kNineByteValue), "");
-  EXPECT_EQ(nine_bytes->put_var_uint64(0, kNineByteValue), 9U);
-  EXPECT_EQ(nine_bytes->get_var_uint64(0, &bytes_read), kNineByteValue);
-  EXPECT_EQ(bytes_read, 9U);
-}
-
 TEST(Buffer, NegativeEqualsReturnsFalse) {
   std::vector<uint8_t> bytes = {1, 2, 3};
   Buffer first(bytes);
@@ -419,13 +378,13 @@ TEST(Buffer, TaggedSmallNegative) {
   std::shared_ptr<Buffer> buffer;
   ASSERT_TRUE(allocate_buffer(8, &buffer));
 
-  EXPECT_EQ(buffer->put_tagged_int64(0, -1), 4U);
+  EXPECT_EQ(buffer->put_tagged_int64_unchecked(0, -1), 4U);
   uint32_t bytes_read = 0;
   EXPECT_EQ(buffer->get_tagged_int64(0, &bytes_read), -1);
   EXPECT_EQ(bytes_read, 4U);
 
   constexpr uint64_t kMaxSmallUnsigned = 0x7fffffff;
-  EXPECT_EQ(buffer->put_tagged_uint64(0, kMaxSmallUnsigned), 4U);
+  EXPECT_EQ(buffer->put_tagged_uint64_unchecked(0, kMaxSmallUnsigned), 4U);
   EXPECT_EQ(buffer->get_tagged_uint64(0, &bytes_read), kMaxSmallUnsigned);
   EXPECT_EQ(bytes_read, 4U);
 
diff --git a/docs/security/deserialization.md b/docs/security/deserialization.md
index a477c0f7e..0e6fcd1f3 100644
--- a/docs/security/deserialization.md
+++ b/docs/security/deserialization.md
@@ -232,14 +232,6 @@ downstream buffer-underflow, type, reference, depth, or 
serializer error is a
 valid rejection. A decoder does not need a new local check merely to replace
 that controlled failure with a more specific or more uniform error.
 
-Non-strict, non-precise, delayed, masked, differently typed, or differently
-layered controlled errors are not security findings. Security remediation MUST
-NOT add checks solely to normalize, sharpen, advance, or otherwise make such an
-error deterministic. This remains true when malformed input decodes to an
-incorrect value, provided the path cannot cause a crash, panic, undefined 
memory
-access, OOM, attacker-controlled memory amplification, or another security
-invariant violation defined by this document.
-
 Tests for malformed input should prove that the root operation fails, cleanup
 remains correct, and any relevant security invariant is preserved. They should
 not pin an exact error type or message when doing so would require additional
diff --git a/java/fory-core/src/main/java/org/apache/fory/Fory.java 
b/java/fory-core/src/main/java/org/apache/fory/Fory.java
index 422455660..a004eef52 100644
--- a/java/fory-core/src/main/java/org/apache/fory/Fory.java
+++ b/java/fory-core/src/main/java/org/apache/fory/Fory.java
@@ -22,7 +22,6 @@ package org.apache.fory;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
-import java.util.Arrays;
 import java.util.IdentityHashMap;
 import java.util.function.Consumer;
 import java.util.function.Function;
@@ -318,7 +317,7 @@ public final class Fory implements BaseFory {
     MemoryBuffer buf = getBuffer();
     buf.writerIndex(0);
     serialize(buf, obj, null);
-    byte[] bytes = copyWrittenBytes(buf);
+    byte[] bytes = buf.getBytes(0, buf.writerIndex());
     resetBuffer();
     return bytes;
   }
@@ -328,7 +327,7 @@ public final class Fory implements BaseFory {
     MemoryBuffer buf = getBuffer();
     buf.writerIndex(0);
     serialize(buf, obj, callback);
-    byte[] bytes = copyWrittenBytes(buf);
+    byte[] bytes = buf.getBytes(0, buf.writerIndex());
     resetBuffer();
     return bytes;
   }
@@ -375,15 +374,6 @@ public final class Fory implements BaseFory {
     serializeToStream(outputStream, buf -> serialize(buf, obj, callback));
   }
 
-  private byte[] copyWrittenBytes(MemoryBuffer buffer) {
-    int length = buffer.writerIndex();
-    if (buffer.isHeapFullyWriteable()) {
-      // Fory owns this writer index; keep public arbitrary-range validation 
out of the root path.
-      return Arrays.copyOf(buffer.getHeapMemory(), length);
-    }
-    return buffer.getBytes(0, length);
-  }
-
   private ForyException processSerializationError(Throwable e) {
     if (!config.trackingRef()) {
       String msg =
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java 
b/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java
index a32cc7a73..8738beab9 100644
--- a/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java
+++ b/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java
@@ -206,21 +206,7 @@ public final class MemoryBuffer {
    * @param streamReader a reader for reading from a stream.
    */
   private MemoryBuffer(byte[] buffer, int offset, int length, ForyStreamReader 
streamReader) {
-    checkArgument(offset >= 0 && length >= 0);
-    if (offset > buffer.length - length) {
-      throw new IllegalArgumentException(
-          String.format("%d exceeds buffer size %d", (long) offset + length, 
buffer.length));
-    }
-    if (AndroidSupport.IS_ANDROID) {
-      MemoryOps.initHeapBuffer(this, buffer, offset, length);
-    } else {
-      this.heapMemory = buffer;
-      this.heapOffset = offset;
-      final long startPos = BYTE_ARRAY_OFFSET + offset;
-      this.address = startPos;
-      this.size = length;
-      this.addressLimit = startPos + length;
-    }
+    initHeapBuffer(buffer, offset, length);
     if (streamReader != null) {
       this.streamReader = streamReader;
     } else {
@@ -343,17 +329,17 @@ public final class MemoryBuffer {
   }
 
   public void initHeapBuffer(byte[] buffer, int offset, int length) {
+    if (buffer == null) {
+      throw new NullPointerException("buffer");
+    }
+    if (offset < 0 || length < 0 || offset > buffer.length - length) {
+      throw new IllegalArgumentException(
+          String.format(
+              "offset %d and length %d exceed buffer size %d", offset, length, 
buffer.length));
+    }
     if (AndroidSupport.IS_ANDROID) {
       MemoryOps.initHeapBuffer(this, buffer, offset, length);
     } else {
-      if (buffer == null) {
-        throw new NullPointerException("buffer");
-      }
-      if (offset < 0 || length < 0 || offset > buffer.length - length) {
-        throw new IllegalArgumentException(
-            String.format(
-                "offset %d and length %d exceed buffer size %d", offset, 
length, buffer.length));
-      }
       this.heapMemory = buffer;
       this.heapOffset = offset;
       final long startPos = BYTE_ARRAY_OFFSET + offset;
@@ -1842,7 +1828,11 @@ public final class MemoryBuffer {
       final int writerIdx = writerIndex;
       final int newIdx = writerIdx + numBytes;
       ensure(newIdx);
-      copyMemory(values, CHAR_ARRAY_OFFSET, heapMemory, address + writerIdx, 
numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(values, CHAR_ARRAY_OFFSET, heapMemory, address + writerIdx, 
numBytes);
+      } else {
+        writeCharsBigEndian(values, 0, values.length, writerIdx);
+      }
       writerIndex = newIdx;
     }
   }
@@ -1858,12 +1848,16 @@ public final class MemoryBuffer {
       final int writerIdx = writerIndex;
       final int newIdx = writerIdx + numBytes;
       ensure(newIdx);
-      copyMemory(
-          values,
-          CHAR_ARRAY_OFFSET + ((long) offset << 1),
-          heapMemory,
-          address + writerIdx,
-          numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(
+            values,
+            CHAR_ARRAY_OFFSET + ((long) offset << 1),
+            heapMemory,
+            address + writerIdx,
+            numBytes);
+      } else {
+        writeCharsBigEndian(values, offset, numElements, writerIdx);
+      }
       writerIndex = newIdx;
     }
   }
@@ -1886,7 +1880,11 @@ public final class MemoryBuffer {
       final int writerIdx = writerIndex;
       final int newIdx = writerIdx + numBytes;
       ensure(newIdx);
-      copyMemory(values, SHORT_ARRAY_OFFSET, heapMemory, address + writerIdx, 
numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(values, SHORT_ARRAY_OFFSET, heapMemory, address + 
writerIdx, numBytes);
+      } else {
+        writeShortsBigEndian(values, 0, values.length, writerIdx);
+      }
       writerIndex = newIdx;
     }
   }
@@ -1902,12 +1900,16 @@ public final class MemoryBuffer {
       final int writerIdx = writerIndex;
       final int newIdx = writerIdx + numBytes;
       ensure(newIdx);
-      copyMemory(
-          values,
-          SHORT_ARRAY_OFFSET + ((long) offset << 1),
-          heapMemory,
-          address + writerIdx,
-          numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(
+            values,
+            SHORT_ARRAY_OFFSET + ((long) offset << 1),
+            heapMemory,
+            address + writerIdx,
+            numBytes);
+      } else {
+        writeShortsBigEndian(values, offset, numElements, writerIdx);
+      }
       writerIndex = newIdx;
     }
   }
@@ -1930,7 +1932,11 @@ public final class MemoryBuffer {
       final int writerIdx = writerIndex;
       final int newIdx = writerIdx + numBytes;
       ensure(newIdx);
-      copyMemory(values, INT_ARRAY_OFFSET, heapMemory, address + writerIdx, 
numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(values, INT_ARRAY_OFFSET, heapMemory, address + writerIdx, 
numBytes);
+      } else {
+        writeIntsBigEndian(values, 0, values.length, writerIdx);
+      }
       writerIndex = newIdx;
     }
   }
@@ -1946,12 +1952,16 @@ public final class MemoryBuffer {
       final int writerIdx = writerIndex;
       final int newIdx = writerIdx + numBytes;
       ensure(newIdx);
-      copyMemory(
-          values,
-          INT_ARRAY_OFFSET + ((long) offset << 2),
-          heapMemory,
-          address + writerIdx,
-          numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(
+            values,
+            INT_ARRAY_OFFSET + ((long) offset << 2),
+            heapMemory,
+            address + writerIdx,
+            numBytes);
+      } else {
+        writeIntsBigEndian(values, offset, numElements, writerIdx);
+      }
       writerIndex = newIdx;
     }
   }
@@ -1974,7 +1984,11 @@ public final class MemoryBuffer {
       final int writerIdx = writerIndex;
       final int newIdx = writerIdx + numBytes;
       ensure(newIdx);
-      copyMemory(values, LONG_ARRAY_OFFSET, heapMemory, address + writerIdx, 
numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(values, LONG_ARRAY_OFFSET, heapMemory, address + writerIdx, 
numBytes);
+      } else {
+        writeLongsBigEndian(values, 0, values.length, writerIdx);
+      }
       writerIndex = newIdx;
     }
   }
@@ -1990,12 +2004,16 @@ public final class MemoryBuffer {
       final int writerIdx = writerIndex;
       final int newIdx = writerIdx + numBytes;
       ensure(newIdx);
-      copyMemory(
-          values,
-          LONG_ARRAY_OFFSET + ((long) offset << 3),
-          heapMemory,
-          address + writerIdx,
-          numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(
+            values,
+            LONG_ARRAY_OFFSET + ((long) offset << 3),
+            heapMemory,
+            address + writerIdx,
+            numBytes);
+      } else {
+        writeLongsBigEndian(values, offset, numElements, writerIdx);
+      }
       writerIndex = newIdx;
     }
   }
@@ -2018,7 +2036,11 @@ public final class MemoryBuffer {
       final int writerIdx = writerIndex;
       final int newIdx = writerIdx + numBytes;
       ensure(newIdx);
-      copyMemory(values, FLOAT_ARRAY_OFFSET, heapMemory, address + writerIdx, 
numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(values, FLOAT_ARRAY_OFFSET, heapMemory, address + 
writerIdx, numBytes);
+      } else {
+        writeFloatsBigEndian(values, 0, values.length, writerIdx);
+      }
       writerIndex = newIdx;
     }
   }
@@ -2034,12 +2056,16 @@ public final class MemoryBuffer {
       final int writerIdx = writerIndex;
       final int newIdx = writerIdx + numBytes;
       ensure(newIdx);
-      copyMemory(
-          values,
-          FLOAT_ARRAY_OFFSET + ((long) offset << 2),
-          heapMemory,
-          address + writerIdx,
-          numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(
+            values,
+            FLOAT_ARRAY_OFFSET + ((long) offset << 2),
+            heapMemory,
+            address + writerIdx,
+            numBytes);
+      } else {
+        writeFloatsBigEndian(values, offset, numElements, writerIdx);
+      }
       writerIndex = newIdx;
     }
   }
@@ -2062,7 +2088,11 @@ public final class MemoryBuffer {
       final int writerIdx = writerIndex;
       final int newIdx = writerIdx + numBytes;
       ensure(newIdx);
-      copyMemory(values, DOUBLE_ARRAY_OFFSET, heapMemory, address + writerIdx, 
numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(values, DOUBLE_ARRAY_OFFSET, heapMemory, address + 
writerIdx, numBytes);
+      } else {
+        writeDoublesBigEndian(values, 0, values.length, writerIdx);
+      }
       writerIndex = newIdx;
     }
   }
@@ -2078,16 +2108,58 @@ public final class MemoryBuffer {
       final int writerIdx = writerIndex;
       final int newIdx = writerIdx + numBytes;
       ensure(newIdx);
-      copyMemory(
-          values,
-          DOUBLE_ARRAY_OFFSET + ((long) offset << 3),
-          heapMemory,
-          address + writerIdx,
-          numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(
+            values,
+            DOUBLE_ARRAY_OFFSET + ((long) offset << 3),
+            heapMemory,
+            address + writerIdx,
+            numBytes);
+      } else {
+        writeDoublesBigEndian(values, offset, numElements, writerIdx);
+      }
       writerIndex = newIdx;
     }
   }
 
+  // Big-endian JVMs use the scalar little-endian primitives here. Keeping 
these methods separate
+  // leaves native bulk copy as the only little-endian hot path.
+  private void writeCharsBigEndian(char[] values, int offset, int length, int 
writerIdx) {
+    for (int i = 0; i < length; i++) {
+      _unsafePutInt16(writerIdx + i * 2, (short) values[offset + i]);
+    }
+  }
+
+  private void writeShortsBigEndian(short[] values, int offset, int length, 
int writerIdx) {
+    for (int i = 0; i < length; i++) {
+      _unsafePutInt16(writerIdx + i * 2, values[offset + i]);
+    }
+  }
+
+  private void writeIntsBigEndian(int[] values, int offset, int length, int 
writerIdx) {
+    for (int i = 0; i < length; i++) {
+      _unsafePutInt32(writerIdx + i * 4, values[offset + i]);
+    }
+  }
+
+  private void writeLongsBigEndian(long[] values, int offset, int length, int 
writerIdx) {
+    for (int i = 0; i < length; i++) {
+      _unsafePutInt64(writerIdx + i * 8, values[offset + i]);
+    }
+  }
+
+  private void writeFloatsBigEndian(float[] values, int offset, int length, 
int writerIdx) {
+    for (int i = 0; i < length; i++) {
+      _unsafePutInt32(writerIdx + i * 4, Float.floatToRawIntBits(values[offset 
+ i]));
+    }
+  }
+
+  private void writeDoublesBigEndian(double[] values, int offset, int length, 
int writerIdx) {
+    for (int i = 0; i < length; i++) {
+      _unsafePutInt64(writerIdx + i * 8, 
Double.doubleToRawLongBits(values[offset + i]));
+    }
+  }
+
   /** For off-heap buffer, this will make a heap buffer internally. */
   public void grow(int neededSize) {
     long length = (long) writerIndex + neededSize;
@@ -2097,7 +2169,7 @@ public final class MemoryBuffer {
   }
 
   private void growSlow(long length) {
-    if (length > Integer.MAX_VALUE) {
+    if (length < 0 || length > Integer.MAX_VALUE) {
       throwOOBException();
     }
     // MemoryAllocator owns the requested-capacity postcondition; do not 
recheck it here.
@@ -2109,16 +2181,8 @@ public final class MemoryBuffer {
     // Negative extents are overflowed writer positions. Compare as unsigned 
so the common path
     // keeps one branch while overflow rejection and allocation stay cold 
before any Unsafe access.
     if (Integer.compareUnsigned(length, size) > 0) {
-      ensureSlow(length);
-    }
-  }
-
-  private void ensureSlow(int length) {
-    if (length < 0) {
-      throwOOBException();
+      growSlow(length);
     }
-    // MemoryAllocator owns the requested-capacity postcondition; do not 
recheck it here.
-    globalAllocator.grow(this, length);
   }
 
   // -------------------------------------------------------------------------
@@ -3535,7 +3599,11 @@ public final class MemoryBuffer {
         streamReader.readChars(values, 0, numBytes >>> 1);
         return;
       }
-      copyMemory(heapMemory, address + readerIdx, values, CHAR_ARRAY_OFFSET, 
numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(heapMemory, address + readerIdx, values, CHAR_ARRAY_OFFSET, 
numBytes);
+      } else {
+        readCharsBigEndian(values, 0, numBytes >>> 1, readerIdx);
+      }
       readerIndex = readerIdx + numBytes;
     }
   }
@@ -3556,7 +3624,11 @@ public final class MemoryBuffer {
         streamReader.readShorts(values, 0, numBytes >>> 1);
         return;
       }
-      copyMemory(heapMemory, address + readerIdx, values, SHORT_ARRAY_OFFSET, 
numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(heapMemory, address + readerIdx, values, 
SHORT_ARRAY_OFFSET, numBytes);
+      } else {
+        readShortsBigEndian(values, 0, numBytes >>> 1, readerIdx);
+      }
       readerIndex = readerIdx + numBytes;
     }
   }
@@ -3577,7 +3649,11 @@ public final class MemoryBuffer {
         streamReader.readInts(values, 0, numBytes >>> 2);
         return;
       }
-      copyMemory(heapMemory, address + readerIdx, values, INT_ARRAY_OFFSET, 
numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(heapMemory, address + readerIdx, values, INT_ARRAY_OFFSET, 
numBytes);
+      } else {
+        readIntsBigEndian(values, 0, numBytes >>> 2, readerIdx);
+      }
       readerIndex = readerIdx + numBytes;
     }
   }
@@ -3598,7 +3674,11 @@ public final class MemoryBuffer {
         streamReader.readLongs(values, 0, numBytes >>> 3);
         return;
       }
-      copyMemory(heapMemory, address + readerIdx, values, LONG_ARRAY_OFFSET, 
numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(heapMemory, address + readerIdx, values, LONG_ARRAY_OFFSET, 
numBytes);
+      } else {
+        readLongsBigEndian(values, 0, numBytes >>> 3, readerIdx);
+      }
       readerIndex = readerIdx + numBytes;
     }
   }
@@ -3619,7 +3699,11 @@ public final class MemoryBuffer {
         streamReader.readFloats(values, 0, numBytes >>> 2);
         return;
       }
-      copyMemory(heapMemory, address + readerIdx, values, FLOAT_ARRAY_OFFSET, 
numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(heapMemory, address + readerIdx, values, 
FLOAT_ARRAY_OFFSET, numBytes);
+      } else {
+        readFloatsBigEndian(values, 0, numBytes >>> 2, readerIdx);
+      }
       readerIndex = readerIdx + numBytes;
     }
   }
@@ -3640,7 +3724,11 @@ public final class MemoryBuffer {
         streamReader.readDoubles(values, 0, numBytes >>> 3);
         return;
       }
-      copyMemory(heapMemory, address + readerIdx, values, DOUBLE_ARRAY_OFFSET, 
numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(heapMemory, address + readerIdx, values, 
DOUBLE_ARRAY_OFFSET, numBytes);
+      } else {
+        readDoublesBigEndian(values, 0, numBytes >>> 3, readerIdx);
+      }
       readerIndex = readerIdx + numBytes;
     }
   }
@@ -3682,12 +3770,16 @@ public final class MemoryBuffer {
         return;
       }
       int readerIdx = readerIndex;
-      copyMemory(
-          heapMemory,
-          address + readerIdx,
-          chars,
-          CHAR_ARRAY_OFFSET + ((long) offset << 1),
-          numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(
+            heapMemory,
+            address + readerIdx,
+            chars,
+            CHAR_ARRAY_OFFSET + ((long) offset << 1),
+            numBytes);
+      } else {
+        readCharsBigEndian(chars, offset, numElements, readerIdx);
+      }
       readerIndex = readerIdx + numBytes;
     }
   }
@@ -3720,12 +3812,16 @@ public final class MemoryBuffer {
         return;
       }
       int readerIdx = readerIndex;
-      copyMemory(
-          heapMemory,
-          address + readerIdx,
-          values,
-          SHORT_ARRAY_OFFSET + ((long) offset << 1),
-          numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(
+            heapMemory,
+            address + readerIdx,
+            values,
+            SHORT_ARRAY_OFFSET + ((long) offset << 1),
+            numBytes);
+      } else {
+        readShortsBigEndian(values, offset, numElements, readerIdx);
+      }
       readerIndex = readerIdx + numBytes;
     }
   }
@@ -3744,12 +3840,16 @@ public final class MemoryBuffer {
         return;
       }
       int readerIdx = readerIndex;
-      copyMemory(
-          heapMemory,
-          address + readerIdx,
-          values,
-          INT_ARRAY_OFFSET + ((long) offset << 2),
-          numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(
+            heapMemory,
+            address + readerIdx,
+            values,
+            INT_ARRAY_OFFSET + ((long) offset << 2),
+            numBytes);
+      } else {
+        readIntsBigEndian(values, offset, numElements, readerIdx);
+      }
       readerIndex = readerIdx + numBytes;
     }
   }
@@ -3768,12 +3868,16 @@ public final class MemoryBuffer {
         return;
       }
       int readerIdx = readerIndex;
-      copyMemory(
-          heapMemory,
-          address + readerIdx,
-          values,
-          LONG_ARRAY_OFFSET + ((long) offset << 3),
-          numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(
+            heapMemory,
+            address + readerIdx,
+            values,
+            LONG_ARRAY_OFFSET + ((long) offset << 3),
+            numBytes);
+      } else {
+        readLongsBigEndian(values, offset, numElements, readerIdx);
+      }
       readerIndex = readerIdx + numBytes;
     }
   }
@@ -3792,12 +3896,16 @@ public final class MemoryBuffer {
         return;
       }
       int readerIdx = readerIndex;
-      copyMemory(
-          heapMemory,
-          address + readerIdx,
-          values,
-          FLOAT_ARRAY_OFFSET + ((long) offset << 2),
-          numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(
+            heapMemory,
+            address + readerIdx,
+            values,
+            FLOAT_ARRAY_OFFSET + ((long) offset << 2),
+            numBytes);
+      } else {
+        readFloatsBigEndian(values, offset, numElements, readerIdx);
+      }
       readerIndex = readerIdx + numBytes;
     }
   }
@@ -3816,16 +3924,56 @@ public final class MemoryBuffer {
         return;
       }
       int readerIdx = readerIndex;
-      copyMemory(
-          heapMemory,
-          address + readerIdx,
-          values,
-          DOUBLE_ARRAY_OFFSET + ((long) offset << 3),
-          numBytes);
+      if (LITTLE_ENDIAN) {
+        copyMemory(
+            heapMemory,
+            address + readerIdx,
+            values,
+            DOUBLE_ARRAY_OFFSET + ((long) offset << 3),
+            numBytes);
+      } else {
+        readDoublesBigEndian(values, offset, numElements, readerIdx);
+      }
       readerIndex = readerIdx + numBytes;
     }
   }
 
+  private void readCharsBigEndian(char[] values, int offset, int length, int 
readerIdx) {
+    for (int i = 0; i < length; i++) {
+      values[offset + i] = (char) _unsafeGetInt16(readerIdx + i * 2);
+    }
+  }
+
+  private void readShortsBigEndian(short[] values, int offset, int length, int 
readerIdx) {
+    for (int i = 0; i < length; i++) {
+      values[offset + i] = _unsafeGetInt16(readerIdx + i * 2);
+    }
+  }
+
+  private void readIntsBigEndian(int[] values, int offset, int length, int 
readerIdx) {
+    for (int i = 0; i < length; i++) {
+      values[offset + i] = _unsafeGetInt32(readerIdx + i * 4);
+    }
+  }
+
+  private void readLongsBigEndian(long[] values, int offset, int length, int 
readerIdx) {
+    for (int i = 0; i < length; i++) {
+      values[offset + i] = _unsafeGetInt64(readerIdx + i * 8);
+    }
+  }
+
+  private void readFloatsBigEndian(float[] values, int offset, int length, int 
readerIdx) {
+    for (int i = 0; i < length; i++) {
+      values[offset + i] = Float.intBitsToFloat(_unsafeGetInt32(readerIdx + i 
* 4));
+    }
+  }
+
+  private void readDoublesBigEndian(double[] values, int offset, int length, 
int readerIdx) {
+    for (int i = 0; i < length; i++) {
+      values[offset + i] = Double.longBitsToDouble(_unsafeGetInt64(readerIdx + 
i * 8));
+    }
+  }
+
   public void checkReadableBytes(int minimumReadableBytes) {
     // use subtract to avoid overflow
     int remaining = size - readerIndex;
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/serializer/PrimitiveArraySerializers.java
 
b/java/fory-core/src/main/java/org/apache/fory/serializer/PrimitiveArraySerializers.java
index 1dc606069..30a333ce5 100644
--- 
a/java/fory-core/src/main/java/org/apache/fory/serializer/PrimitiveArraySerializers.java
+++ 
b/java/fory-core/src/main/java/org/apache/fory/serializer/PrimitiveArraySerializers.java
@@ -27,7 +27,6 @@ import org.apache.fory.context.ReadContext;
 import org.apache.fory.context.WriteContext;
 import org.apache.fory.exception.DeserializationException;
 import org.apache.fory.memory.MemoryBuffer;
-import org.apache.fory.memory.NativeByteOrder;
 import org.apache.fory.resolver.TypeResolver;
 import org.apache.fory.type.BFloat16Array;
 import org.apache.fory.type.Float16Array;
@@ -138,11 +137,7 @@ public final class PrimitiveArraySerializers {
         buf.checkReadableBytes(size);
         reserveArray(readContext, numElements, 2);
         short[] values = new short[numElements];
-        if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-          buf.readInt16ArrayBytes(values, size);
-        } else {
-          readInt16BySwapEndian(buf, values, numElements);
-        }
+        buf.readInt16ArrayBytes(values, size);
         return values;
       }
       int size = buffer.readVarUInt32Small7();
@@ -156,11 +151,7 @@ public final class PrimitiveArraySerializers {
       buffer.checkReadableBytes(size);
       reserveArray(readContext, numElements, 2);
       short[] values = new short[numElements];
-      if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-        buffer.readInt16ArrayBytes(values, size);
-      } else {
-        readInt16BySwapEndian(buffer, values, numElements);
-      }
+      buffer.readInt16ArrayBytes(values, size);
       return values;
     }
   }
@@ -280,28 +271,13 @@ public final class PrimitiveArraySerializers {
         throw new UnsupportedOperationException();
       }
       if (writeContext.getBufferCallback() == null) {
-        if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-          buffer.writeCharsWithSize(value);
-        } else {
-          writeCharBySwapEndian(buffer, value);
-        }
+        buffer.writeCharsWithSize(value);
       } else {
         writeContext.writeBufferObject(
             new PrimitiveArrayBufferObject(value, Types.UINT16_ARRAY, 2, 
value.length));
       }
     }
 
-    private void writeCharBySwapEndian(MemoryBuffer buffer, char[] value) {
-      int idx = buffer.writerIndex();
-      int length = value.length;
-      buffer.ensure(idx + 5 + length * 2);
-      idx += buffer._unsafeWriteVarUInt32(length * 2);
-      for (int i = 0; i < length; i++) {
-        buffer._unsafePutInt16(idx + i * 2, (short) value[i]);
-      }
-      buffer._unsafeWriterIndex(idx + length * 2);
-    }
-
     @Override
     public char[] copy(CopyContext copyContext, char[] originArray) {
       return Arrays.copyOf(originArray, originArray.length);
@@ -323,11 +299,7 @@ public final class PrimitiveArraySerializers {
         buf.checkReadableBytes(size);
         reserveArray(readContext, numElements, 2);
         char[] values = new char[numElements];
-        if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-          buf.readCharArrayBytes(values, size);
-        } else {
-          readCharBySwapEndian(buf, values, numElements);
-        }
+        buf.readCharArrayBytes(values, size);
         return values;
       }
       int size = buffer.readVarUInt32Small7();
@@ -341,22 +313,8 @@ public final class PrimitiveArraySerializers {
       buffer.checkReadableBytes(size);
       reserveArray(readContext, numElements, 2);
       char[] values = new char[numElements];
-      if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-        buffer.readCharArrayBytes(values, size);
-      } else {
-        readCharBySwapEndian(buffer, values, numElements);
-      }
-      return values;
-    }
-
-    private void readCharBySwapEndian(MemoryBuffer buffer, char[] values, int 
numElements) {
-      int size = numElements << 1;
-      // Do not loop through MemoryBuffer._unsafeGet* here; those helpers 
carry Android dispatch.
-      // Copy the body bytes once, then byte-swap the destination values 
locally.
       buffer.readCharArrayBytes(values, size);
-      for (int i = 0; i < numElements; i++) {
-        values[i] = Character.reverseBytes(values[i]);
-      }
+      return values;
     }
   }
 
@@ -394,28 +352,13 @@ public final class PrimitiveArraySerializers {
           writeInt32Compressed(buffer, value);
           return;
         }
-        if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-          buffer.writeIntsWithSize(value);
-        } else {
-          writeInt32BySwapEndian(buffer, value);
-        }
+        buffer.writeIntsWithSize(value);
       } else {
         writeContext.writeBufferObject(
             new PrimitiveArrayBufferObject(value, Types.INT32_ARRAY, 4, 
value.length));
       }
     }
 
-    private void writeInt32BySwapEndian(MemoryBuffer buffer, int[] value) {
-      int idx = buffer.writerIndex();
-      int length = value.length;
-      buffer.ensure(idx + 5 + length * 4);
-      idx += buffer._unsafeWriteVarUInt32(length * 4);
-      for (int i = 0; i < length; i++) {
-        buffer._unsafePutInt32(idx + i * 4, value[i]);
-      }
-      buffer._unsafeWriterIndex(idx + length * 4);
-    }
-
     @Override
     public int[] copy(CopyContext copyContext, int[] originArray) {
       return Arrays.copyOf(originArray, originArray.length);
@@ -435,11 +378,7 @@ public final class PrimitiveArraySerializers {
         reserveArray(readContext, numElements, 4);
         int[] values = new int[numElements];
         if (size > 0) {
-          if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-            buf.readInt32ArrayBytes(values, size);
-          } else {
-            readInt32BySwapEndian(buf, values, numElements);
-          }
+          buf.readInt32ArrayBytes(values, size);
         }
         return values;
       }
@@ -458,25 +397,11 @@ public final class PrimitiveArraySerializers {
       reserveArray(readContext, numElements, 4);
       int[] values = new int[numElements];
       if (size > 0) {
-        if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-          buffer.readInt32ArrayBytes(values, size);
-        } else {
-          readInt32BySwapEndian(buffer, values, numElements);
-        }
+        buffer.readInt32ArrayBytes(values, size);
       }
       return values;
     }
 
-    private void readInt32BySwapEndian(MemoryBuffer buffer, int[] values, int 
numElements) {
-      int size = numElements << 2;
-      // Do not loop through MemoryBuffer._unsafeGet* here; those helpers 
carry Android dispatch.
-      // Copy the body bytes once, then byte-swap the destination values 
locally.
-      buffer.readInt32ArrayBytes(values, size);
-      for (int i = 0; i < numElements; i++) {
-        values[i] = Integer.reverseBytes(values[i]);
-      }
-    }
-
     private void writeInt32Compressed(MemoryBuffer buffer, int[] value) {
       buffer.writeVarUInt32Small7(value.length);
       for (int i : value) {
@@ -519,28 +444,13 @@ public final class PrimitiveArraySerializers {
           writeInt64Compressed(buffer, value, config.longEncoding());
           return;
         }
-        if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-          buffer.writeLongsWithSize(value);
-        } else {
-          writeInt64BySwapEndian(buffer, value);
-        }
+        buffer.writeLongsWithSize(value);
       } else {
         writeContext.writeBufferObject(
             new PrimitiveArrayBufferObject(value, Types.INT64_ARRAY, 8, 
value.length));
       }
     }
 
-    private void writeInt64BySwapEndian(MemoryBuffer buffer, long[] value) {
-      int idx = buffer.writerIndex();
-      int length = value.length;
-      buffer.ensure(idx + 5 + length * 8);
-      idx += buffer._unsafeWriteVarUInt32(length * 8);
-      for (int i = 0; i < length; i++) {
-        buffer._unsafePutInt64(idx + i * 8, value[i]);
-      }
-      buffer._unsafeWriterIndex(idx + length * 8);
-    }
-
     @Override
     public long[] copy(CopyContext copyContext, long[] originArray) {
       return Arrays.copyOf(originArray, originArray.length);
@@ -560,11 +470,7 @@ public final class PrimitiveArraySerializers {
         reserveArray(readContext, numElements, 8);
         long[] values = new long[numElements];
         if (size > 0) {
-          if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-            buf.readInt64ArrayBytes(values, size);
-          } else {
-            readInt64BySwapEndian(buf, values, numElements);
-          }
+          buf.readInt64ArrayBytes(values, size);
         }
         return values;
       }
@@ -583,25 +489,11 @@ public final class PrimitiveArraySerializers {
       reserveArray(readContext, numElements, 8);
       long[] values = new long[numElements];
       if (size > 0) {
-        if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-          buffer.readInt64ArrayBytes(values, size);
-        } else {
-          readInt64BySwapEndian(buffer, values, numElements);
-        }
+        buffer.readInt64ArrayBytes(values, size);
       }
       return values;
     }
 
-    private void readInt64BySwapEndian(MemoryBuffer buffer, long[] values, int 
numElements) {
-      int size = numElements << 3;
-      // Do not loop through MemoryBuffer._unsafeGet* here; those helpers 
carry Android dispatch.
-      // Copy the body bytes once, then byte-swap the destination values 
locally.
-      buffer.readInt64ArrayBytes(values, size);
-      for (int i = 0; i < numElements; i++) {
-        values[i] = Long.reverseBytes(values[i]);
-      }
-    }
-
     private void writeInt64Compressed(
         MemoryBuffer buffer, long[] value, Int64Encoding longEncoding) {
       int length = value.length;
@@ -648,28 +540,13 @@ public final class PrimitiveArraySerializers {
     public void write(WriteContext writeContext, float[] value) {
       MemoryBuffer buffer = writeContext.getBuffer();
       if (writeContext.getBufferCallback() == null) {
-        if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-          buffer.writeFloatsWithSize(value);
-        } else {
-          writeFloat32BySwapEndian(buffer, value);
-        }
+        buffer.writeFloatsWithSize(value);
       } else {
         writeContext.writeBufferObject(
             new PrimitiveArrayBufferObject(value, Types.FLOAT32_ARRAY, 4, 
value.length));
       }
     }
 
-    private void writeFloat32BySwapEndian(MemoryBuffer buffer, float[] value) {
-      int idx = buffer.writerIndex();
-      int length = value.length;
-      buffer.ensure(idx + 5 + length * 4);
-      idx += buffer._unsafeWriteVarUInt32(length * 4);
-      for (int i = 0; i < length; i++) {
-        buffer._unsafePutInt32(idx + i * 4, Float.floatToRawIntBits(value[i]));
-      }
-      buffer._unsafeWriterIndex(idx + length * 4);
-    }
-
     @Override
     public float[] copy(CopyContext copyContext, float[] originArray) {
       return Arrays.copyOf(originArray, originArray.length);
@@ -688,11 +565,7 @@ public final class PrimitiveArraySerializers {
         buf.checkReadableBytes(size);
         reserveArray(readContext, numElements, 4);
         float[] values = new float[numElements];
-        if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-          buf.readFloat32ArrayBytes(values, size);
-        } else {
-          readFloat32BySwapEndian(buf, values, numElements);
-        }
+        buf.readFloat32ArrayBytes(values, size);
         return values;
       }
       int size = buffer.readVarUInt32Small7();
@@ -706,22 +579,8 @@ public final class PrimitiveArraySerializers {
       buffer.checkReadableBytes(size);
       reserveArray(readContext, numElements, 4);
       float[] values = new float[numElements];
-      if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-        buffer.readFloat32ArrayBytes(values, size);
-      } else {
-        readFloat32BySwapEndian(buffer, values, numElements);
-      }
-      return values;
-    }
-
-    private void readFloat32BySwapEndian(MemoryBuffer buffer, float[] values, 
int numElements) {
-      int size = numElements << 2;
-      // Do not loop through MemoryBuffer._unsafeGet* here; those helpers 
carry Android dispatch.
-      // Copy the body bytes once, then byte-swap the destination values 
locally.
       buffer.readFloat32ArrayBytes(values, size);
-      for (int i = 0; i < numElements; i++) {
-        values[i] = 
Float.intBitsToFloat(Integer.reverseBytes(Float.floatToRawIntBits(values[i])));
-      }
+      return values;
     }
   }
 
@@ -734,28 +593,13 @@ public final class PrimitiveArraySerializers {
     public void write(WriteContext writeContext, double[] value) {
       MemoryBuffer buffer = writeContext.getBuffer();
       if (writeContext.getBufferCallback() == null) {
-        if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-          buffer.writeDoublesWithSize(value);
-        } else {
-          writeFloat64BySwapEndian(buffer, value);
-        }
+        buffer.writeDoublesWithSize(value);
       } else {
         writeContext.writeBufferObject(
             new PrimitiveArrayBufferObject(value, Types.FLOAT64_ARRAY, 8, 
value.length));
       }
     }
 
-    private void writeFloat64BySwapEndian(MemoryBuffer buffer, double[] value) 
{
-      int idx = buffer.writerIndex();
-      int length = value.length;
-      buffer.ensure(idx + 5 + length * 8);
-      idx += buffer._unsafeWriteVarUInt32(length * 8);
-      for (int i = 0; i < length; i++) {
-        buffer._unsafePutInt64(idx + i * 8, 
Double.doubleToRawLongBits(value[i]));
-      }
-      buffer._unsafeWriterIndex(idx + length * 8);
-    }
-
     @Override
     public double[] copy(CopyContext copyContext, double[] originArray) {
       return Arrays.copyOf(originArray, originArray.length);
@@ -774,11 +618,7 @@ public final class PrimitiveArraySerializers {
         buf.checkReadableBytes(size);
         reserveArray(readContext, numElements, 8);
         double[] values = new double[numElements];
-        if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-          buf.readFloat64ArrayBytes(values, size);
-        } else {
-          readFloat64BySwapEndian(buf, values, numElements);
-        }
+        buf.readFloat64ArrayBytes(values, size);
         return values;
       }
       int size = buffer.readVarUInt32Small7();
@@ -792,23 +632,8 @@ public final class PrimitiveArraySerializers {
       buffer.checkReadableBytes(size);
       reserveArray(readContext, numElements, 8);
       double[] values = new double[numElements];
-      if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-        buffer.readFloat64ArrayBytes(values, size);
-      } else {
-        readFloat64BySwapEndian(buffer, values, numElements);
-      }
-      return values;
-    }
-
-    private void readFloat64BySwapEndian(MemoryBuffer buffer, double[] values, 
int numElements) {
-      int size = numElements << 3;
-      // Do not loop through MemoryBuffer._unsafeGet* here; those helpers 
carry Android dispatch.
-      // Copy the body bytes once, then byte-swap the destination values 
locally.
       buffer.readFloat64ArrayBytes(values, size);
-      for (int i = 0; i < numElements; i++) {
-        values[i] =
-            
Double.longBitsToDouble(Long.reverseBytes(Double.doubleToRawLongBits(values[i])));
-      }
+      return values;
     }
   }
 
@@ -858,38 +683,13 @@ public final class PrimitiveArraySerializers {
   private static void writeShortBits(WriteContext writeContext, short[] value) 
{
     MemoryBuffer buffer = writeContext.getBuffer();
     if (writeContext.getBufferCallback() == null) {
-      if (NativeByteOrder.IS_LITTLE_ENDIAN) {
-        buffer.writeShortsWithSize(value);
-      } else {
-        writeInt16BySwapEndian(buffer, value);
-      }
+      buffer.writeShortsWithSize(value);
     } else {
       writeContext.writeBufferObject(
           new PrimitiveArrayBufferObject(value, Types.INT16_ARRAY, 2, 
value.length));
     }
   }
 
-  private static void writeInt16BySwapEndian(MemoryBuffer buffer, short[] 
value) {
-    int idx = buffer.writerIndex();
-    int length = value.length;
-    buffer.ensure(idx + 5 + length * 2);
-    idx += buffer._unsafeWriteVarUInt32(length * 2);
-    for (int i = 0; i < length; i++) {
-      buffer._unsafePutInt16(idx + i * 2, value[i]);
-    }
-    buffer._unsafeWriterIndex(idx + length * 2);
-  }
-
-  private static void readInt16BySwapEndian(MemoryBuffer buffer, short[] 
values, int numElements) {
-    int size = numElements << 1;
-    // Do not loop through MemoryBuffer._unsafeGet* here; those helpers carry 
Android dispatch.
-    // Copy the body bytes once, then byte-swap the destination values locally.
-    buffer.readInt16ArrayBytes(values, size);
-    for (int i = 0; i < numElements; i++) {
-      values[i] = Short.reverseBytes(values[i]);
-    }
-  }
-
   public static void registerDefaultSerializers(TypeResolver resolver) {
     resolver.registerInternalSerializer(byte[].class, new 
ByteArraySerializer(resolver));
     resolver.registerInternalSerializer(char[].class, new 
CharArraySerializer(resolver));
diff --git 
a/java/fory-core/src/main/java25/org/apache/fory/memory/MemoryBuffer.java 
b/java/fory-core/src/main/java25/org/apache/fory/memory/MemoryBuffer.java
index c8ce159d1..2e3a834b7 100644
--- a/java/fory-core/src/main/java25/org/apache/fory/memory/MemoryBuffer.java
+++ b/java/fory-core/src/main/java25/org/apache/fory/memory/MemoryBuffer.java
@@ -157,12 +157,7 @@ public final class MemoryBuffer {
       throw new IllegalArgumentException(
           String.format("%d exceeds buffer size %d", offset + length, 
buffer.length));
     }
-    this.heapMemory = buffer;
-    this.heapOffset = offset;
-    final long startPos = BYTE_ARRAY_OFFSET + offset;
-    this.address = startPos;
-    this.size = length;
-    this.addressLimit = startPos + length;
+    initHeapBuffer(buffer, offset, length);
     if (streamReader != null) {
       this.streamReader = streamReader;
     } else {
@@ -1921,7 +1916,11 @@ public final class MemoryBuffer {
     final int writerIdx = writerIndex;
     final int newIdx = writerIdx + numBytes;
     ensure(newIdx);
-    writeCharsFromArray(address + writerIdx, values, CHAR_ARRAY_OFFSET + 
offset, numBytes);
+    if (LITTLE_ENDIAN) {
+      writeCharsFromArray(address + writerIdx, values, CHAR_ARRAY_OFFSET + 
offset, numBytes);
+    } else {
+      writeCharsBigEndian(values, offset, numElements, writerIdx);
+    }
     writerIndex = newIdx;
   }
 
@@ -1940,7 +1939,11 @@ public final class MemoryBuffer {
     final int writerIdx = writerIndex;
     final int newIdx = writerIdx + numBytes;
     ensure(newIdx);
-    writeShortsFromArray(address + writerIdx, values, SHORT_ARRAY_OFFSET + 
offset, numBytes);
+    if (LITTLE_ENDIAN) {
+      writeShortsFromArray(address + writerIdx, values, SHORT_ARRAY_OFFSET + 
offset, numBytes);
+    } else {
+      writeShortsBigEndian(values, offset, numElements, writerIdx);
+    }
     writerIndex = newIdx;
   }
 
@@ -1959,7 +1962,11 @@ public final class MemoryBuffer {
     final int writerIdx = writerIndex;
     final int newIdx = writerIdx + numBytes;
     ensure(newIdx);
-    writeIntsFromArray(address + writerIdx, values, INT_ARRAY_OFFSET + offset, 
numBytes);
+    if (LITTLE_ENDIAN) {
+      writeIntsFromArray(address + writerIdx, values, INT_ARRAY_OFFSET + 
offset, numBytes);
+    } else {
+      writeIntsBigEndian(values, offset, numElements, writerIdx);
+    }
     writerIndex = newIdx;
   }
 
@@ -1978,7 +1985,11 @@ public final class MemoryBuffer {
     final int writerIdx = writerIndex;
     final int newIdx = writerIdx + numBytes;
     ensure(newIdx);
-    writeLongsFromArray(address + writerIdx, values, LONG_ARRAY_OFFSET + 
offset, numBytes);
+    if (LITTLE_ENDIAN) {
+      writeLongsFromArray(address + writerIdx, values, LONG_ARRAY_OFFSET + 
offset, numBytes);
+    } else {
+      writeLongsBigEndian(values, offset, numElements, writerIdx);
+    }
     writerIndex = newIdx;
   }
 
@@ -1997,7 +2008,11 @@ public final class MemoryBuffer {
     final int writerIdx = writerIndex;
     final int newIdx = writerIdx + numBytes;
     ensure(newIdx);
-    writeFloatsFromArray(address + writerIdx, values, FLOAT_ARRAY_OFFSET + 
offset, numBytes);
+    if (LITTLE_ENDIAN) {
+      writeFloatsFromArray(address + writerIdx, values, FLOAT_ARRAY_OFFSET + 
offset, numBytes);
+    } else {
+      writeFloatsBigEndian(values, offset, numElements, writerIdx);
+    }
     writerIndex = newIdx;
   }
 
@@ -2016,10 +2031,52 @@ public final class MemoryBuffer {
     final int writerIdx = writerIndex;
     final int newIdx = writerIdx + numBytes;
     ensure(newIdx);
-    writeDoublesFromArray(address + writerIdx, values, DOUBLE_ARRAY_OFFSET + 
offset, numBytes);
+    if (LITTLE_ENDIAN) {
+      writeDoublesFromArray(address + writerIdx, values, DOUBLE_ARRAY_OFFSET + 
offset, numBytes);
+    } else {
+      writeDoublesBigEndian(values, offset, numElements, writerIdx);
+    }
     writerIndex = newIdx;
   }
 
+  // Big-endian JVMs use the scalar little-endian primitives here. Keeping 
these methods separate
+  // leaves native bulk copy as the only little-endian hot path.
+  private void writeCharsBigEndian(char[] values, int offset, int length, int 
writerIdx) {
+    for (int i = 0; i < length; i++) {
+      _unsafePutInt16(writerIdx + i * 2, (short) values[offset + i]);
+    }
+  }
+
+  private void writeShortsBigEndian(short[] values, int offset, int length, 
int writerIdx) {
+    for (int i = 0; i < length; i++) {
+      _unsafePutInt16(writerIdx + i * 2, values[offset + i]);
+    }
+  }
+
+  private void writeIntsBigEndian(int[] values, int offset, int length, int 
writerIdx) {
+    for (int i = 0; i < length; i++) {
+      _unsafePutInt32(writerIdx + i * 4, values[offset + i]);
+    }
+  }
+
+  private void writeLongsBigEndian(long[] values, int offset, int length, int 
writerIdx) {
+    for (int i = 0; i < length; i++) {
+      _unsafePutInt64(writerIdx + i * 8, values[offset + i]);
+    }
+  }
+
+  private void writeFloatsBigEndian(float[] values, int offset, int length, 
int writerIdx) {
+    for (int i = 0; i < length; i++) {
+      _unsafePutInt32(writerIdx + i * 4, Float.floatToRawIntBits(values[offset 
+ i]));
+    }
+  }
+
+  private void writeDoublesBigEndian(double[] values, int offset, int length, 
int writerIdx) {
+    for (int i = 0; i < length; i++) {
+      _unsafePutInt64(writerIdx + i * 8, 
Double.doubleToRawLongBits(values[offset + i]));
+    }
+  }
+
   /** For off-heap buffer, this will make a heap buffer internally. */
   public void grow(int neededSize) {
     int length = writerIndex + neededSize;
@@ -3299,7 +3356,11 @@ public final class MemoryBuffer {
       streamReader.readChars(values, 0, numBytes >>> 1);
       return;
     }
-    readCharsToArray(address + readerIdx, values, CHAR_ARRAY_OFFSET, numBytes);
+    if (LITTLE_ENDIAN) {
+      readCharsToArray(address + readerIdx, values, CHAR_ARRAY_OFFSET, 
numBytes);
+    } else {
+      readCharsBigEndian(values, 0, numBytes >>> 1, readerIdx);
+    }
     readerIndex = readerIdx + numBytes;
   }
 
@@ -3314,7 +3375,11 @@ public final class MemoryBuffer {
       streamReader.readShorts(values, 0, numBytes >>> 1);
       return;
     }
-    readShortsToArray(address + readerIdx, values, SHORT_ARRAY_OFFSET, 
numBytes);
+    if (LITTLE_ENDIAN) {
+      readShortsToArray(address + readerIdx, values, SHORT_ARRAY_OFFSET, 
numBytes);
+    } else {
+      readShortsBigEndian(values, 0, numBytes >>> 1, readerIdx);
+    }
     readerIndex = readerIdx + numBytes;
   }
 
@@ -3329,7 +3394,11 @@ public final class MemoryBuffer {
       streamReader.readInts(values, 0, numBytes >>> 2);
       return;
     }
-    readIntsToArray(address + readerIdx, values, INT_ARRAY_OFFSET, numBytes);
+    if (LITTLE_ENDIAN) {
+      readIntsToArray(address + readerIdx, values, INT_ARRAY_OFFSET, numBytes);
+    } else {
+      readIntsBigEndian(values, 0, numBytes >>> 2, readerIdx);
+    }
     readerIndex = readerIdx + numBytes;
   }
 
@@ -3344,7 +3413,11 @@ public final class MemoryBuffer {
       streamReader.readLongs(values, 0, numBytes >>> 3);
       return;
     }
-    readLongsToArray(address + readerIdx, values, LONG_ARRAY_OFFSET, numBytes);
+    if (LITTLE_ENDIAN) {
+      readLongsToArray(address + readerIdx, values, LONG_ARRAY_OFFSET, 
numBytes);
+    } else {
+      readLongsBigEndian(values, 0, numBytes >>> 3, readerIdx);
+    }
     readerIndex = readerIdx + numBytes;
   }
 
@@ -3359,7 +3432,11 @@ public final class MemoryBuffer {
       streamReader.readFloats(values, 0, numBytes >>> 2);
       return;
     }
-    readFloatsToArray(address + readerIdx, values, FLOAT_ARRAY_OFFSET, 
numBytes);
+    if (LITTLE_ENDIAN) {
+      readFloatsToArray(address + readerIdx, values, FLOAT_ARRAY_OFFSET, 
numBytes);
+    } else {
+      readFloatsBigEndian(values, 0, numBytes >>> 2, readerIdx);
+    }
     readerIndex = readerIdx + numBytes;
   }
 
@@ -3374,7 +3451,11 @@ public final class MemoryBuffer {
       streamReader.readDoubles(values, 0, numBytes >>> 3);
       return;
     }
-    readDoublesToArray(address + readerIdx, values, DOUBLE_ARRAY_OFFSET, 
numBytes);
+    if (LITTLE_ENDIAN) {
+      readDoublesToArray(address + readerIdx, values, DOUBLE_ARRAY_OFFSET, 
numBytes);
+    } else {
+      readDoublesBigEndian(values, 0, numBytes >>> 3, readerIdx);
+    }
     readerIndex = readerIdx + numBytes;
   }
 
@@ -3407,7 +3488,11 @@ public final class MemoryBuffer {
       return;
     }
     int readerIdx = readerIndex;
-    readCharsToArray(address + readerIdx, chars, CHAR_ARRAY_OFFSET + offset, 
numBytes);
+    if (LITTLE_ENDIAN) {
+      readCharsToArray(address + readerIdx, chars, CHAR_ARRAY_OFFSET + offset, 
numBytes);
+    } else {
+      readCharsBigEndian(chars, offset, numElements, readerIdx);
+    }
     readerIndex = readerIdx + numBytes;
   }
 
@@ -3436,7 +3521,11 @@ public final class MemoryBuffer {
       return;
     }
     int readerIdx = readerIndex;
-    readShortsToArray(address + readerIdx, values, SHORT_ARRAY_OFFSET + 
offset, numBytes);
+    if (LITTLE_ENDIAN) {
+      readShortsToArray(address + readerIdx, values, SHORT_ARRAY_OFFSET + 
offset, numBytes);
+    } else {
+      readShortsBigEndian(values, offset, numElements, readerIdx);
+    }
     readerIndex = readerIdx + numBytes;
   }
 
@@ -3451,7 +3540,11 @@ public final class MemoryBuffer {
       return;
     }
     int readerIdx = readerIndex;
-    readIntsToArray(address + readerIdx, values, INT_ARRAY_OFFSET + offset, 
numBytes);
+    if (LITTLE_ENDIAN) {
+      readIntsToArray(address + readerIdx, values, INT_ARRAY_OFFSET + offset, 
numBytes);
+    } else {
+      readIntsBigEndian(values, offset, numElements, readerIdx);
+    }
     readerIndex = readerIdx + numBytes;
   }
 
@@ -3466,7 +3559,11 @@ public final class MemoryBuffer {
       return;
     }
     int readerIdx = readerIndex;
-    readLongsToArray(address + readerIdx, values, LONG_ARRAY_OFFSET + offset, 
numBytes);
+    if (LITTLE_ENDIAN) {
+      readLongsToArray(address + readerIdx, values, LONG_ARRAY_OFFSET + 
offset, numBytes);
+    } else {
+      readLongsBigEndian(values, offset, numElements, readerIdx);
+    }
     readerIndex = readerIdx + numBytes;
   }
 
@@ -3481,7 +3578,11 @@ public final class MemoryBuffer {
       return;
     }
     int readerIdx = readerIndex;
-    readFloatsToArray(address + readerIdx, values, FLOAT_ARRAY_OFFSET + 
offset, numBytes);
+    if (LITTLE_ENDIAN) {
+      readFloatsToArray(address + readerIdx, values, FLOAT_ARRAY_OFFSET + 
offset, numBytes);
+    } else {
+      readFloatsBigEndian(values, offset, numElements, readerIdx);
+    }
     readerIndex = readerIdx + numBytes;
   }
 
@@ -3496,10 +3597,50 @@ public final class MemoryBuffer {
       return;
     }
     int readerIdx = readerIndex;
-    readDoublesToArray(address + readerIdx, values, DOUBLE_ARRAY_OFFSET + 
offset, numBytes);
+    if (LITTLE_ENDIAN) {
+      readDoublesToArray(address + readerIdx, values, DOUBLE_ARRAY_OFFSET + 
offset, numBytes);
+    } else {
+      readDoublesBigEndian(values, offset, numElements, readerIdx);
+    }
     readerIndex = readerIdx + numBytes;
   }
 
+  private void readCharsBigEndian(char[] values, int offset, int length, int 
readerIdx) {
+    for (int i = 0; i < length; i++) {
+      values[offset + i] = (char) _unsafeGetInt16(readerIdx + i * 2);
+    }
+  }
+
+  private void readShortsBigEndian(short[] values, int offset, int length, int 
readerIdx) {
+    for (int i = 0; i < length; i++) {
+      values[offset + i] = _unsafeGetInt16(readerIdx + i * 2);
+    }
+  }
+
+  private void readIntsBigEndian(int[] values, int offset, int length, int 
readerIdx) {
+    for (int i = 0; i < length; i++) {
+      values[offset + i] = _unsafeGetInt32(readerIdx + i * 4);
+    }
+  }
+
+  private void readLongsBigEndian(long[] values, int offset, int length, int 
readerIdx) {
+    for (int i = 0; i < length; i++) {
+      values[offset + i] = _unsafeGetInt64(readerIdx + i * 8);
+    }
+  }
+
+  private void readFloatsBigEndian(float[] values, int offset, int length, int 
readerIdx) {
+    for (int i = 0; i < length; i++) {
+      values[offset + i] = Float.intBitsToFloat(_unsafeGetInt32(readerIdx + i 
* 4));
+    }
+  }
+
+  private void readDoublesBigEndian(double[] values, int offset, int length, 
int readerIdx) {
+    for (int i = 0; i < length; i++) {
+      values[offset + i] = Double.longBitsToDouble(_unsafeGetInt64(readerIdx + 
i * 8));
+    }
+  }
+
   public void checkReadableBytes(int minimumReadableBytes) {
     // use subtract to avoid overflow
     int remaining = size - readerIndex;
diff --git 
a/java/fory-core/src/test/java/org/apache/fory/memory/MemoryBufferTest.java 
b/java/fory-core/src/test/java/org/apache/fory/memory/MemoryBufferTest.java
index 093bd3945..99fe14686 100644
--- a/java/fory-core/src/test/java/org/apache/fory/memory/MemoryBufferTest.java
+++ b/java/fory-core/src/test/java/org/apache/fory/memory/MemoryBufferTest.java
@@ -649,62 +649,128 @@ public class MemoryBufferTest {
 
   private void assertTypedArrayCopies(MemoryBuffer buffer) {
     byte[] bytes = {1, 2, 3, 4};
-    int byteOffset = buffer.writerIndex();
-    buffer.writeBytes(bytes);
+    buffer.copyFromByteArray(0, bytes, 0, bytes.length);
     byte[] byteCopy = new byte[bytes.length];
-    buffer.copyToByteArray(byteOffset, byteCopy, 0, bytes.length);
+    buffer.copyToByteArray(0, byteCopy, 0, bytes.length);
     assertEquals(byteCopy, bytes);
 
     boolean[] booleans = {true, false, true};
-    int booleanOffset = buffer.writerIndex();
-    buffer.writeBooleans(booleans);
+    buffer.copyFromBooleanArray(0, booleans, 0, booleans.length);
     boolean[] booleanCopy = new boolean[booleans.length];
-    buffer.copyToBooleanArray(booleanOffset, booleanCopy, 0, booleans.length);
+    buffer.copyToBooleanArray(0, booleanCopy, 0, booleans.length);
     assertEquals(booleanCopy, booleans);
 
     char[] chars = {'a', 0x1234, Character.MAX_VALUE};
-    int charOffset = buffer.writerIndex();
-    buffer.writeChars(chars);
+    buffer.copyFromCharArray(0, chars, 0, chars.length * Character.BYTES);
     char[] charCopy = new char[chars.length];
-    buffer.copyToCharArray(charOffset, charCopy, 0, chars.length * 
Character.BYTES);
+    buffer.copyToCharArray(0, charCopy, 0, chars.length * Character.BYTES);
     assertEquals(charCopy, chars);
 
     short[] shorts = {1, -2, Short.MAX_VALUE};
-    int shortOffset = buffer.writerIndex();
-    buffer.writeShorts(shorts);
+    buffer.copyFromShortArray(0, shorts, 0, shorts.length * Short.BYTES);
     short[] shortCopy = new short[shorts.length];
-    buffer.copyToShortArray(shortOffset, shortCopy, 0, shorts.length * 
Short.BYTES);
+    buffer.copyToShortArray(0, shortCopy, 0, shorts.length * Short.BYTES);
     assertEquals(shortCopy, shorts);
 
     int[] ints = {1, -2, Integer.MIN_VALUE};
-    int intOffset = buffer.writerIndex();
-    buffer.writeInts(ints);
+    buffer.copyFromIntArray(0, ints, 0, ints.length * Integer.BYTES);
     int[] intCopy = new int[ints.length];
-    buffer.copyToIntArray(intOffset, intCopy, 0, ints.length * Integer.BYTES);
+    buffer.copyToIntArray(0, intCopy, 0, ints.length * Integer.BYTES);
     assertEquals(intCopy, ints);
 
     long[] longs = {1L, -2L, Long.MAX_VALUE};
-    int longOffset = buffer.writerIndex();
-    buffer.writeLongs(longs);
+    buffer.copyFromLongArray(0, longs, 0, longs.length * Long.BYTES);
     long[] longCopy = new long[longs.length];
-    buffer.copyToLongArray(longOffset, longCopy, 0, longs.length * Long.BYTES);
+    buffer.copyToLongArray(0, longCopy, 0, longs.length * Long.BYTES);
     assertEquals(longCopy, longs);
 
     float[] floats = {1.5f, -2.5f, Float.MAX_VALUE};
-    int floatOffset = buffer.writerIndex();
-    buffer.writeFloats(floats);
+    buffer.copyFromFloatArray(0, floats, 0, floats.length * Float.BYTES);
     float[] floatCopy = new float[floats.length];
-    buffer.copyToFloatArray(floatOffset, floatCopy, 0, floats.length * 
Float.BYTES);
+    buffer.copyToFloatArray(0, floatCopy, 0, floats.length * Float.BYTES);
     assertEquals(floatCopy, floats);
 
     double[] doubles = {1.5d, -2.5d, Double.MAX_VALUE};
-    int doubleOffset = buffer.writerIndex();
-    buffer.writeDoubles(doubles);
+    buffer.copyFromDoubleArray(0, doubles, 0, doubles.length * Double.BYTES);
     double[] doubleCopy = new double[doubles.length];
-    buffer.copyToDoubleArray(doubleOffset, doubleCopy, 0, doubles.length * 
Double.BYTES);
+    buffer.copyToDoubleArray(0, doubleCopy, 0, doubles.length * Double.BYTES);
     assertEquals(doubleCopy, doubles);
   }
 
+  @Test
+  public void testPrimitiveArrayLittleEndian() {
+    assertPrimitiveArrayLittleEndian(MemoryUtils.buffer(64));
+    
assertPrimitiveArrayLittleEndian(MemoryUtils.wrap(ByteBuffer.allocateDirect(64)));
+  }
+
+  private void assertPrimitiveArrayLittleEndian(MemoryBuffer buffer) {
+    char[] chars = {0x1234};
+    short[] shorts = {(short) 0x1234};
+    int[] ints = {0x12345678};
+    long[] longs = {0x0102030405060708L};
+    float[] floats = {1.0f};
+    double[] doubles = {1.0d};
+    buffer.writeChars(chars);
+    buffer.writeShorts(shorts);
+    buffer.writeInts(ints);
+    buffer.writeLongs(longs);
+    buffer.writeFloats(floats);
+    buffer.writeDoubles(doubles);
+
+    assertEquals(
+        buffer.getBytes(0, buffer.writerIndex()),
+        new byte[] {
+          0x34,
+          0x12,
+          0x34,
+          0x12,
+          0x78,
+          0x56,
+          0x34,
+          0x12,
+          0x08,
+          0x07,
+          0x06,
+          0x05,
+          0x04,
+          0x03,
+          0x02,
+          0x01,
+          0x00,
+          0x00,
+          (byte) 0x80,
+          0x3f,
+          0x00,
+          0x00,
+          0x00,
+          0x00,
+          0x00,
+          0x00,
+          (byte) 0xf0,
+          0x3f
+        });
+
+    buffer.readerIndex(0);
+    char[] readChars = new char[1];
+    short[] readShorts = new short[1];
+    int[] readInts = new int[1];
+    long[] readLongs = new long[1];
+    float[] readFloats = new float[1];
+    double[] readDoubles = new double[1];
+    buffer.readChars(readChars, 0, 1);
+    buffer.readShorts(readShorts, 0, 1);
+    buffer.readInts(readInts, 0, 1);
+    buffer.readLongs(readLongs, 0, 1);
+    buffer.readFloats(readFloats, 0, 1);
+    buffer.readDoubles(readDoubles, 0, 1);
+    assertEquals(readChars, chars);
+    assertEquals(readShorts, shorts);
+    assertEquals(readInts, ints);
+    assertEquals(readLongs, longs);
+    assertEquals(readFloats, floats);
+    assertEquals(readDoubles, doubles);
+  }
+
   @Test
   public void testWritePrimitiveArrayWithSizeEmbedded() {
     MemoryBuffer buf = MemoryUtils.buffer(16);
diff --git a/python/pyfory/cpp/pyfory.cc b/python/pyfory/cpp/pyfory.cc
index 8c0c37ddc..de38b357a 100644
--- a/python/pyfory/cpp/pyfory.cc
+++ b/python/pyfory/cpp/pyfory.cc
@@ -956,7 +956,7 @@ static int write_primitive_sequence(PyObject **items, 
Py_ssize_t size,
         }
         const uint64_t zigzag =
             (static_cast<uint64_t>(v) << 1) ^ static_cast<uint64_t>(v >> 63);
-        offset += buffer->put_var_uint64(offset, zigzag);
+        offset += buffer->put_var_uint64_unchecked(offset, zigzag);
       }
       buffer->increase_writer_index(offset - writer_index);
     }
@@ -980,7 +980,7 @@ static int write_primitive_sequence(PyObject **items, 
Py_ssize_t size,
         }
         const uint32_t zigzag =
             (static_cast<uint32_t>(v) << 1) ^ static_cast<uint32_t>(v >> 31);
-        offset += buffer->put_var_uint32(offset, zigzag);
+        offset += buffer->put_var_uint32_unchecked(offset, zigzag);
       }
       buffer->increase_writer_index(offset - writer_index);
     }
diff --git a/python/pyfory/number.pxi b/python/pyfory/number.pxi
index 317cb10ad..79cc2bc5e 100644
--- a/python/pyfory/number.pxi
+++ b/python/pyfory/number.pxi
@@ -61,31 +61,18 @@ cdef class _ForyArray:
     cpdef Py_ssize_t _size(self):
         raise NotImplementedError
 
-    # These cpdef helpers are public; normalize here so direct calls share 
sequence bounds semantics.
-    cpdef object _get(self, Py_ssize_t index):
-        return self._get_unchecked(self._normalize_index(index))
-
     cdef object _get_unchecked(self, Py_ssize_t index):
         raise NotImplementedError
 
-    cpdef _set(self, Py_ssize_t index, object value):
-        self._set_unchecked(self._normalize_index(index), value)
-
     cdef _set_unchecked(self, Py_ssize_t index, object value):
         raise NotImplementedError
 
     cpdef _append(self, object value):
         raise NotImplementedError
 
-    cpdef _insert(self, Py_ssize_t index, object value):
-        self._insert_unchecked(self._normalize_insert_index(index), value)
-
     cdef _insert_unchecked(self, Py_ssize_t index, object value):
         raise NotImplementedError
 
-    cpdef _delete(self, Py_ssize_t index):
-        self._delete_unchecked(self._normalize_index(index))
-
     cdef _delete_unchecked(self, Py_ssize_t index):
         raise NotImplementedError
 
diff --git a/python/pyfory/tests/test_buffer.py 
b/python/pyfory/tests/test_buffer.py
index 3a29bb646..f13590a2d 100644
--- a/python/pyfory/tests/test_buffer.py
+++ b/python/pyfory/tests/test_buffer.py
@@ -341,43 +341,6 @@ def test_bit_helper_ranges():
         set_bit_to(buffer, 2**32 - 1, 2**32 - 1, True)
 
 
[email protected](
-    "array_type,values",
-    [
-        (pyfory.BoolArray, [True]),
-        (pyfory.Int8Array, [1]),
-        (pyfory.Int16Array, [1]),
-        (pyfory.Int32Array, [1]),
-        (pyfory.Int64Array, [1]),
-        (pyfory.UInt8Array, [1]),
-        (pyfory.UInt16Array, [1]),
-        (pyfory.UInt32Array, [1]),
-        (pyfory.UInt64Array, [1]),
-        (pyfory.Float16Array, [1.0]),
-        (pyfory.BFloat16Array, [1.0]),
-        (pyfory.Float32Array, [1.0]),
-        (pyfory.Float64Array, [1.0]),
-    ],
-)
-def test_native_array_range_owner(array_type, values):
-    value = array_type(values)
-    assert value[0] == values[0]
-    assert value._get(-1) == values[0]
-    value._set(-1, values[0])
-    with pytest.raises(Exception):
-        _ = value[1]
-    with pytest.raises(Exception):
-        value._get(1)
-    with pytest.raises(Exception):
-        value._set(1, values[0])
-    with pytest.raises(Exception):
-        value._delete(1)
-    value._insert(99, values[0])
-    assert len(value) == 2
-    value._delete(-1)
-    assert value == values
-
-
 def test_hash_buffer_empty_input():
     assert pyfory.mmh3.hash_buffer(b"") == (0, 0)
 
diff --git a/rust/fory-core/src/buffer.rs b/rust/fory-core/src/buffer.rs
index e6d1da493..53a24b4cc 100644
--- a/rust/fory-core/src/buffer.rs
+++ b/rust/fory-core/src/buffer.rs
@@ -1100,6 +1100,7 @@ impl<'a> Reader<'a> {
         let slice = self.slice_after_cursor();
 
         if slice.len() >= 8 {
+            // Decode speculatively without advancing so malformed input 
leaves the cursor intact.
             let bulk = LittleEndian::read_u64(&slice[..8]);
             let mut result = bulk & 0x7F;
             let mut read_idx = start;
diff --git a/rust/tests/tests/test_buffer.rs b/rust/tests/tests/test_buffer.rs
index f18e4b370..3ce7c3c38 100644
--- a/rust/tests/tests/test_buffer.rs
+++ b/rust/tests/tests/test_buffer.rs
@@ -112,6 +112,11 @@ fn test_var_u36_bad_framing() {
         let mut reader = Reader::new(&bytes);
         assert!(reader.read_var_u36_small().is_err());
     }
+
+    let padded = [0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0x2a, 0x2b];
+    let mut reader = Reader::new(&padded);
+    assert!(reader.read_var_u36_small().is_err());
+    assert_eq!(reader.get_cursor(), 0);
 }
 
 #[test]
diff --git a/swift/Sources/Fory/ByteBuffer.swift 
b/swift/Sources/Fory/ByteBuffer.swift
index 7fdb95481..0c8227983 100644
--- a/swift/Sources/Fory/ByteBuffer.swift
+++ b/swift/Sources/Fory/ByteBuffer.swift
@@ -192,13 +192,6 @@ public final class ByteBuffer {
         cursor -= amount
     }
 
-    @usableFromInline
-    @inline(__always)
-    internal func moveBackUnchecked(_ amount: Int) {
-        // Hot read owners use this only to rewind bytes they just consumed 
successfully.
-        cursor -= amount
-    }
-
     @inlinable
     @inline(__always)
     internal func appendLittleEndian<T: FixedWidthInteger>(_ value: T) {
@@ -768,7 +761,7 @@ public final class ByteBuffer {
         if (first & 1) == 0 {
             return Int64(first >> 1)
         }
-        moveBackUnchecked(3)
+        cursor -= 3
         return try readInt64()
     }
 
@@ -778,7 +771,7 @@ public final class ByteBuffer {
         if (first & 1) == 0 {
             return UInt64(first >> 1)
         }
-        moveBackUnchecked(3)
+        cursor -= 3
         return try readUInt64()
     }
 
@@ -851,6 +844,8 @@ public final class ByteBuffer {
                 }
             }
             if isASCII {
+                // ASCII bytes are always valid UTF-8.
+                // swiftlint:disable:next optional_data_string_conversion
                 return String(decoding: utf8Bytes, as: UTF8.self)
             }
             if #available(macOS 15.0, iOS 18.0, tvOS 18.0, watchOS 11.0, 
visionOS 2.0, *) {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to