Repository: aviramha/ormsgpack (language: python)

Issue:
Issues building aarch64 binary wheels
ormsgpack says it is tested on aarch64 in the README file.

I'm hitting build errors on aarch64 with all of the last several versions
on
rustc 1.67.0 stable
rustc 1.69.0-nightly (d7948c843 2023-01-26)

I manually went through master and the last 4 or so tagged versions:

master, 1.2.4, 1.2.3 (fails in src/serialize/writer.rs)

```
error[E0308]: mismatched types=========> ] 63/64: ormsgpack                                                                                          
  --> src/serialize/writer.rs:38:14
   |
38 |             (&(*self.bytes.cast::<PyBytesObject>()).ob_sval as *const [i8; 1] as *mut u8)
   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found array `[i8; 1]`
```


1.2.2, 1.2.1,1.1.0  (fails in packed_simd_2)

```
Error in packed_simd:

   Compiling packed_simd_2 v0.3.7
    Building error: expected one of `!` or `::`, found keyword `mod`
   --> /home/awagner/.cargo/registry/src/github.com-1ecc6299db9ec823/packed_simd_2-0.3.7/src/lib.rs:347:7
    |
347 | crate mod llvm {
    |       ^^^ expected one of `!` or `::`

[===============>           ] 33/53: num-traits(build), pyo3-build-config(build), packed_simd_2, libc                                   
error: aborting due to previous error

```

I need this for a project at work, so I'll probably take a crack at fixing this up, but if there's a known-good compiler version and git version for aarch64 that would be quite welcome!

Thanks for the useful library!


Discussion / hints:
I have studied the code, and I am at a complete loss as to why ormsgpack compiles on x86 but not aarch64, even with environments as identical as I can get them.

on aarch64:
rustc 1.69.0-nightly (dc1d9d50f 2023-01-31)
Python 3.9.16
ormsgpack 1.2.4

on x86-64:
rustc 1.69.0-nightly (dc1d9d50f 2023-01-31)
Python 3.9.16
ormsgpack 1.2.4

I even diffed the Cargo.lock files from both machines, and they're identical.

It's compiling on "cargo check", so the issue is in typechecking, long before code generation. This is a language level issue so the cpu platfform should not even matter. For clarity, the line that's failing to compile (but only on the ARM box) is still:

```
error[E0308]: mismatched types=========> ] 63/64: ormsgpack                                                                                          
  --> src/serialize/writer.rs:38:14
   |
38 |             (&(*self.bytes.cast::<PyBytesObject>()).ob_sval as *const [i8; 1] as *mut u8)
   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found array `[i8; 1]`
```
The types are different between different architectures probably, so it's not a language level. 
I will take a look into it.

Fix patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ea679462..04c9e9f5 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,11 +1,17 @@
-
 name: Release
-on:
+# This should almost always run, but upload binaries only on tag.
+on: 
+  pull_request:
+    branches: [ master ]
   workflow_dispatch:
   push:
+    branches: [ master ]
     tags:
       - '*.*.*'
-
+# Cancel previous runs on the same PR.
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
 
 jobs:
   release_manylinux:
@@ -18,7 +24,10 @@ jobs:
     env:
       TWINE_PASSWORD: ${{secrets.TWINE_PASSWORD}}
       TWINE_USERNAME: ${{secrets.TWINE_USERNAME}}
-      RUSTFLAGS: -C target-cpu=k8
+      CC: "gcc"
+      CFLAGS: "-O2 -fno-plt"
+      LDFLAGS: "-O2 -flto -Wl,--as-needed"
+      CARGO_UNSTABLE_SPARSE_REGISTRY: "true"
 
     steps:
       - uses: actions/checkout@v2
@@ -27,15 +36,17 @@ jobs:
           profile: minimal
           toolchain: nightly
           override: true
+          components: rust-src
       - run: yum install -y libffi libffi-devel openssl openssl-devel
       - run: /opt/python/${{ matrix.python-path }}/bin/python -m venv .venv
       - run: .venv/bin/pip install -U pip wheel
       - run: .venv/bin/pip install -U twine maturin
       - run: .venv/bin/pip install -r requirements.txt
-      - run: .venv/bin/maturin build --release --strip --manylinux 2014 -i /opt/python/${{ matrix.python-path }}/bin/python --target x86_64-unknown-linux-gnu
+      - run: .venv/bin/maturin build --features=unstable-simd --release --strip --manylinux 2014 -i /opt/python/${{ matrix.python-path }}/bin/python --target x86_64-unknown-linux-gnu
       - run: .venv/bin/pip install ormsgpack --no-index -f target/wheels
       - run: .venv/bin/pytest
-      - run: .venv/bin/twine upload --non-interactive --skip-existing target/wheels/*
+      - if: startsWith(github.ref, 'refs/tags')
+        run: .venv/bin/twine upload --non-interactive --skip-existing target/wheels/*
   release_windows:
     name: Release windows
     runs-on: windows-latest
@@ -45,7 +56,6 @@ jobs:
     env:
       TWINE_PASSWORD: ${{secrets.TWINE_PASSWORD}}
       TWINE_USERNAME: ${{secrets.TWINE_USERNAME}}
-      RUSTFLAGS: -C target-cpu=k8
     steps:
       - uses: actions/checkout@v2
       - uses: actions-rs/toolchain@v1
@@ -53,6 +63,7 @@ jobs:
           profile: minimal
           toolchain: nightly
           override: true
+          components: rust-src
       - name: Set up Python
         uses: actions/setup-python@v2
         with:
@@ -62,7 +73,8 @@ jobs:
       - run: maturin build --release --strip -i $pythonLocation"python.exe"
       - run: pip install ormsgpack --no-index -f target/wheels
       - run: pytest
-      - run: twine upload --non-interactive --skip-existing target\wheels\*
+      - if: startsWith(github.ref, 'refs/tags')
+        run: twine upload --non-interactive --skip-existing target\wheels\*
 
   release_macos_x64:
     name: Release macOS (x86_64)
@@ -73,7 +85,6 @@ jobs:
     env:
       TWINE_PASSWORD: ${{secrets.TWINE_PASSWORD}}
       TWINE_USERNAME: ${{secrets.TWINE_USERNAME}}
-      RUSTFLAGS: -C target-cpu=k8
     steps:
       - uses: actions/checkout@v2
       - uses: actions-rs/toolchain@v1
@@ -81,16 +92,24 @@ jobs:
           profile: minimal
           toolchain: nightly
           override: true
+          components: rust-src
       - name: Set up Python
         uses: actions/setup-python@v2
         with:
           python-version: ${{ matrix.python-version }}
       - run: python -m pip install -U pip wheel twine maturin
       - run: pip install -r requirements.txt
-      - run: maturin build --release --strip --manylinux off -i $pythonLocation/python --target x86_64-apple-darwin
+      - env:
+          CC: "clang"
+          CFLAGS: "-O2 -fno-plt -flto=thin"
+          LDFLAGS: "-O2 -flto=thin -fuse-ld=lld -Wl,--as-needed"
+          RUSTFLAGS: "-C linker=clang -C target-feature=+sse4.2"
+          CARGO_UNSTABLE_SPARSE_REGISTRY: "true"
+        run: maturin build --release --strip --manylinux off -i $pythonLocation/python --features=unstable-simd -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort --target x86_64-apple-darwin
       - run: pip install ormsgpack --no-index -f target/wheels
       - run: pytest
-      - run: twine upload --non-interactive --skip-existing target/wheels/*
+      - if: startsWith(github.ref, 'refs/tags')
+        run: twine upload --non-interactive --skip-existing target/wheels/*
 
   release_macos_universal:
     name: Release macOS (universal)
@@ -109,13 +128,21 @@ jobs:
           toolchain: nightly
           override: true
           target: aarch64-apple-darwin
+          components: rust-src
       - name: Set up Python
         uses: actions/setup-python@v2
         with:
           python-version: ${{ matrix.python-version }}
       - run: python -m pip install -U pip wheel twine maturin
-      - run: PATH=$HOME/.cargo/bin:$PATH PYO3_CROSS_LIB_DIR=$(python -c "import sysconfig;print(sysconfig.get_config_var('LIBDIR'))") maturin build --release --strip --cargo-extra-args="--features=unstable-simd" --universal2
-      - run: twine upload --non-interactive --skip-existing target/wheels/*
+      - env:
+          CC: "clang"
+          CFLAGS: "-O2 -fno-plt -flto=thin"
+          LDFLAGS: "-O2 -flto=thin -fuse-ld=lld -Wl,--as-needed"
+          RUSTFLAGS: "-C linker=clang"
+          CARGO_UNSTABLE_SPARSE_REGISTRY: "true"
+        run: PATH=$HOME/.cargo/bin:$PATH PYO3_CROSS_LIB_DIR=$(python -c "import sysconfig;print(sysconfig.get_config_var('LIBDIR'))") maturin build --release --strip --features=unstable-simd --universal2
+      - if: startsWith(github.ref, 'refs/tags')
+        run: twine upload --non-interactive --skip-existing target/wheels/*
   release_sdist:
     name: Release sdist
     runs-on: ubuntu-latest
@@ -129,6 +156,7 @@ jobs:
           profile: minimal
           toolchain: nightly
           override: true
+          components: rust-src
       - name: Set up Python
         uses: actions/setup-python@v2
         with:
@@ -136,4 +164,5 @@ jobs:
       - run: python -m pip install -U pip wheel twine maturin
       - run: pip install -r requirements.txt
       - run: maturin sdist
-      - run: twine upload --non-interactive --skip-existing target/wheels/*
+      - if: startsWith(github.ref, 'refs/tags')
+        run: twine upload --non-interactive --skip-existing target/wheels/*
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 90c9b047..21a0715d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
 # Changelog
 
+## 1.2.5 02/02/2023
+
+### Fixed
+
+- aarch64 build on macOS. Took `src/serialize/writer.rs` from upstream orjson. by @ijl
+- Fix release on aarch64 to match orjson's upstream.
+
+### Misc
+
+- update dependencies
+
 ## 1.2.4 16/11/2022
 
 ### Misc
diff --git a/Cargo.lock b/Cargo.lock
index 942434e4..f084fc47 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -54,9 +54,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "encoding_rs"
-version = "0.8.31"
+version = "0.8.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b"
+checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
 dependencies = [
  "cfg-if",
  "packed_simd_2",
@@ -81,15 +81,15 @@ checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb"
 
 [[package]]
 name = "itoa"
-version = "1.0.2"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
+checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
 
 [[package]]
 name = "libc"
-version = "0.2.126"
+version = "0.2.139"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
 
 [[package]]
 name = "libm"
@@ -99,9 +99,9 @@ checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
 
 [[package]]
 name = "lock_api"
-version = "0.4.7"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
+checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -127,9 +127,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.16.0"
+version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
 
 [[package]]
 name = "ormsgpack"
@@ -174,9 +174,9 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.3"
+version = "0.9.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
+checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
 dependencies = [
  "cfg-if",
  "libc",
@@ -187,9 +187,9 @@ dependencies = [
 
 [[package]]
 name = "paste"
-version = "1.0.7"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
+checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
 
 [[package]]
 name = "pyo3"
@@ -227,9 +227,9 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.2.13"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
+checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
 dependencies = [
  "bitflags",
 ]
@@ -247,9 +247,9 @@ dependencies = [
 
 [[package]]
 name = "rmp-serde"
-version = "1.1.0"
+version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25786b0d276110195fa3d6f3f31299900cf71dfbd6c28450f3f58a0e7f7a347e"
+checksum = "c5b13be192e0220b8afb7222aa5813cb62cc269ebb5cac346ca6487681d2913e"
 dependencies = [
  "byteorder",
  "rmp",
@@ -258,9 +258,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.10"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
+checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
 
 [[package]]
 name = "scopeguard"
@@ -270,9 +270,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
 [[package]]
 name = "serde"
-version = "1.0.137"
+version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
 
 [[package]]
 name = "simdutf8"
@@ -282,15 +282,15 @@ checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
 
 [[package]]
 name = "smallvec"
-version = "1.8.1"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
 
 [[package]]
 name = "target-lexicon"
-version = "0.12.4"
+version = "0.12.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1"
+checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d"
 
 [[package]]
 name = "version_check"
@@ -306,43 +306,66 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "windows-sys"
-version = "0.36.1"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
 dependencies = [
+ "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
  "windows_i686_gnu",
  "windows_i686_msvc",
  "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
  "windows_x86_64_msvc",
 ]
 
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
+
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.36.1"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.36.1"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.36.1"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.36.1"
+version = "0.42.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.36.1"
+version = "0.42.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
diff --git a/Cargo.toml b/Cargo.toml
index 9171c361..79ef94b0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,7 +37,7 @@ unstable-simd = [
 ]
 
 [dependencies]
-ahash = { version = "0.7.6", default_features = false }
+ahash = { version = "0.7", default_features = false }
 associative-cache = { version = "1" }
 bytecount = { version = "^0.6.2", default_features = false, features = ["runtime-dispatch-simd"] }
 encoding_rs = { version = "0.8", default_features = false }
diff --git a/src/lib.rs b/src/lib.rs
index 21d237c3..1c2d7b97 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,4 @@
 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
-
 #![cfg_attr(feature = "unstable-simd", feature(core_intrinsics))]
 #![allow(unused_unsafe)]
 #![allow(clippy::missing_safety_doc)]
diff --git a/src/serialize/default.rs b/src/serialize/default.rs
index f71dc1f4..49a374b5 100644
--- a/src/serialize/default.rs
+++ b/src/serialize/default.rs
@@ -12,7 +12,7 @@ use std::ptr::NonNull;
 #[inline(never)]
 fn format_err(ptr: *mut pyo3::ffi::PyObject) -> String {
     let name = unsafe { CStr::from_ptr((*ob_type!(ptr)).tp_name).to_string_lossy() };
-    format_args!("Type is not msgpack serializable: {}", name).to_string()
+    format_args!("Type is not msgpack serializable: {name}").to_string()
 }
 
 pub struct DefaultSerializer {
diff --git a/src/serialize/serializer.rs b/src/serialize/serializer.rs
index d478e1d7..d9633d9e 100644
--- a/src/serialize/serializer.rs
+++ b/src/serialize/serializer.rs
@@ -26,7 +26,7 @@ pub fn serialize(
     default: Option<NonNull<pyo3::ffi::PyObject>>,
     opts: Opt,
 ) -> Result<NonNull<pyo3::ffi::PyObject>, String> {
-    let mut buf = BytesWriter::new();
+    let mut buf = BytesWriter::default();
     let obj = PyObjectSerializer::new(ptr, opts, 0, 0, default);
     let mut ser = rmp_serde::Serializer::new(&mut buf);
     let res = obj.serialize(&mut ser);
diff --git a/src/serialize/uuid.rs b/src/serialize/uuid.rs
index 1b24f02a..6fdafcd9 100644
--- a/src/serialize/uuid.rs
+++ b/src/serialize/uuid.rs
@@ -37,7 +37,7 @@ impl UUID {
         }
 
         let mut hexadecimal: SmallVec<[u8; 32]> = SmallVec::with_capacity(32);
-        write!(hexadecimal, "{:032x}", value).unwrap();
+        write!(hexadecimal, "{value:032x}").unwrap();
 
         buf.extend_from_slice(&hexadecimal[..8]);
         buf.push(b'-');
diff --git a/src/serialize/writer.rs b/src/serialize/writer.rs
index 7ad2b282..80218fa2 100644
--- a/src/serialize/writer.rs
+++ b/src/serialize/writer.rs
@@ -1,8 +1,9 @@
 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
 
 use crate::ffi::PyBytesObject;
-use core::ptr::NonNull;
 use pyo3::ffi::*;
+use std::os::raw::c_char;
+use std::ptr::NonNull;
 
 const BUFFER_LENGTH: usize = 1024;
 
@@ -13,7 +14,7 @@ pub struct BytesWriter {
 }
 
 impl BytesWriter {
-    pub fn new() -> Self {
+    pub fn default() -> Self {
         BytesWriter {
             cap: BUFFER_LENGTH,
             len: 0,
@@ -26,42 +27,55 @@ impl BytesWriter {
 
     pub fn finish(&mut self) -> NonNull<PyObject> {
         unsafe {
+            std::ptr::write(self.buffer_ptr(), 0);
             (*self.bytes.cast::<PyVarObject>()).ob_size = self.len as Py_ssize_t;
-            self.resize(self.len as isize);
+            self.resize(self.len);
             NonNull::new_unchecked(self.bytes as *mut PyObject)
         }
     }
 
-    #[inline]
     fn buffer_ptr(&self) -> *mut u8 {
         unsafe {
-            (&(*self.bytes.cast::<PyBytesObject>()).ob_sval as *const [i8; 1] as *mut u8)
-                .add(self.len)
+            std::mem::transmute::<*mut [c_char; 1], *mut u8>(std::ptr::addr_of_mut!(
+                (*self.bytes).ob_sval
+            ))
+            .add(self.len)
         }
     }
 
-    #[inline(always)]
-    pub fn resize(&mut self, len: isize) {
+    #[inline]
+    pub fn resize(&mut self, len: usize) {
+        self.cap = len;
         unsafe {
             _PyBytes_Resize(
-                &mut self.bytes as *mut *mut PyBytesObject as *mut *mut PyObject,
-                len as _,
+                std::ptr::addr_of_mut!(self.bytes) as *mut *mut PyBytesObject as *mut *mut PyObject,
+                len as isize,
             );
         }
     }
 
     #[cold]
+    #[inline(never)]
     fn grow(&mut self, len: usize) {
-        while len >= self.cap {
-            self.cap *= 2;
+        let mut cap = self.cap;
+        while len >= cap {
+            if len < 262144 {
+                cap *= 4;
+            } else {
+                cap *= 2;
+            }
         }
-        self.resize(self.cap as isize);
+        self.resize(cap);
     }
 }
 
 impl std::io::Write for BytesWriter {
-    #[inline]
-    fn write(&mut self, buf: &[u8]) -> std::result::Result<usize, std::io::Error> {
+    fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
+        let _ = self.write_all(buf);
+        Ok(buf.len())
+    }
+
+    fn write_all(&mut self, buf: &[u8]) -> Result<(), std::io::Error> {
         let to_write = buf.len();
         let end_length = self.len + to_write;
         if unlikely!(end_length > self.cap) {
@@ -71,15 +85,130 @@ impl std::io::Write for BytesWriter {
             std::ptr::copy_nonoverlapping(buf.as_ptr() as *const u8, self.buffer_ptr(), to_write);
         };
         self.len = end_length;
-        Ok(to_write)
+        Ok(())
+    }
+
+    fn flush(&mut self) -> Result<(), std::io::Error> {
+        Ok(())
+    }
+}
+
+#[allow(dead_code)]
+// hack based on saethlin's research and patch in https://github.com/serde-rs/json/issues/766
+pub trait WriteExt: std::io::Write {
+    #[inline]
+    fn as_mut_buffer_ptr(&mut self) -> *mut u8 {
+        std::ptr::null_mut()
+    }
+
+    #[inline]
+    fn reserve(&mut self, len: usize) {
+        let _ = len;
     }
+
     #[inline]
-    fn write_all(&mut self, buf: &[u8]) -> std::result::Result<(), std::io::Error> {
-        let _ = self.write(buf);
+    fn set_written(&mut self, len: usize) {
+        let _ = len;
+    }
+
+    #[inline]
+    fn write_str(&mut self, val: &str) -> std::result::Result<(), std::io::Error> {
+        let _ = val;
         Ok(())
     }
+
+    #[inline]
+    unsafe fn write_reserved_fragment(
+        &mut self,
+        val: &[u8],
+    ) -> std::result::Result<(), std::io::Error> {
+        let _ = val;
+        Ok(())
+    }
+
     #[inline]
-    fn flush(&mut self) -> std::result::Result<(), std::io::Error> {
+    unsafe fn write_reserved_punctuation(
+        &mut self,
+        val: u8,
+    ) -> std::result::Result<(), std::io::Error> {
+        let _ = val;
+        Ok(())
+    }
+
+    #[inline]
+    unsafe fn write_reserved_indent(
+        &mut self,
+        len: usize,
+    ) -> std::result::Result<(), std::io::Error> {
+        let _ = len;
+        Ok(())
+    }
+}
+
+#[allow(dead_code)]
+impl WriteExt for &mut BytesWriter {
+    #[inline(always)]
+    fn as_mut_buffer_ptr(&mut self) -> *mut u8 {
+        self.buffer_ptr()
+    }
+
+    #[inline(always)]
+    fn reserve(&mut self, len: usize) {
+        let end_length = self.len + len;
+        if unlikely!(end_length > self.cap) {
+            self.grow(end_length);
+        }
+    }
+
+    #[inline(always)]
+    fn set_written(&mut self, len: usize) {
+        self.len += len;
+    }
+
+    fn write_str(&mut self, val: &str) -> Result<(), std::io::Error> {
+        let to_write = val.len();
+        let end_length = self.len + to_write + 2;
+        if unlikely!(end_length > self.cap) {
+            self.grow(end_length);
+        }
+        unsafe {
+            let ptr = self.buffer_ptr();
+            std::ptr::write(ptr, b'"');
+            std::ptr::copy_nonoverlapping(val.as_ptr() as *const u8, ptr.add(1), to_write);
+            std::ptr::write(ptr.add(to_write + 1), b'"');
+        };
+        self.len = end_length;
+        Ok(())
+    }
+
+    unsafe fn write_reserved_fragment(
+        &mut self,
+        val: &[u8],
+    ) -> std::result::Result<(), std::io::Error> {
+        let to_write = val.len();
+        unsafe {
+            std::ptr::copy_nonoverlapping(val.as_ptr() as *const u8, self.buffer_ptr(), to_write);
+        };
+        self.len += to_write;
+        Ok(())
+    }
+
+    #[inline(always)]
+    unsafe fn write_reserved_punctuation(
+        &mut self,
+        val: u8,
+    ) -> std::result::Result<(), std::io::Error> {
+        unsafe { std::ptr::write(self.buffer_ptr(), val) };
+        self.len += 1;
+        Ok(())
+    }
+
+    #[inline(always)]
+    unsafe fn write_reserved_indent(&mut self, len: usize) -> Result<(), std::io::Error> {
+        unsafe {
+            std::ptr::write_bytes(self.buffer_ptr(), b' ', len);
+        };
+        self.len += len;
         Ok(())
     }
 }


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index a112b20d..24e695d9 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -4,6 +4,11 @@ on:
   pull_request:
     branches: [ master ]
 
+# Cancel previous runs on the same PR.
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
 name: Tests & Linting
 
 jobs: