Skip to content

Commit 3297670

Browse files
authored
Merge pull request #57 from simd-lite/fix-write-string-rust
Update dependencies and improve iterator implementations
2 parents 9b034cf + 530749a commit 3297670

File tree

12 files changed

+117
-92
lines changed

12 files changed

+117
-92
lines changed

.github/workflows/quality.yaml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- uses: actions-rs/toolchain@v1
2424
with:
2525
profile: minimal
26-
toolchain: "1.64.0"
26+
toolchain: "1.85.0"
2727
override: true
2828
components: clippy, rustfmt
2929
- name: Validate cargo format
@@ -52,8 +52,10 @@ jobs:
5252
rustflags:
5353
- flags: "-C target-cpu=native"
5454
name: "avx2"
55-
- flags: "-C target-cpu=native -C target-feature=-avx2"
55+
- flags: "-C target-feature=-avx2"
5656
name: "sse"
57+
- flags: "-C target-feature=-avx2,-sse4.2"
58+
name: "compat"
5759
features:
5860
- "128bit"
5961
- "custom-types"
@@ -66,7 +68,7 @@ jobs:
6668
- uses: actions-rs/toolchain@v1
6769
with:
6870
profile: minimal
69-
toolchain: "1.64.0"
71+
toolchain: "1.85.0"
7072
override: true
7173
components: llvm-tools-preview
7274
- name: Install cargo-llcm-cov
@@ -82,4 +84,4 @@ jobs:
8284
file: ./lcov.txt
8385
flags: "${{ matrix.features }}-${{ matrix.rustflags.name }}"
8486
fail_ci_if_error: ${{ github.event_name == 'pull_request' }}
85-
verbose: true
87+
verbose: true

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22
name = "value-trait"
33
version = "0.10.1"
44
authors = ["Heinz N. Gies <[email protected]>"]
5-
edition = "2021"
5+
edition = "2024"
66
license = "Apache-2.0/MIT"
77
description = "Traits to deal with JSONesque values"
88
repository = "https://github.com/simd-lite/value-trait"
99
readme = "README.md"
1010
documentation = "https://docs.rs/value-trait"
11-
rust-version = "1.64"
11+
rust-version = "1.85"
1212

1313

1414
[dependencies]
1515
itoa = "1"
1616
ryu = "1"
17-
halfbrown = { version = "0.2", optional = true }
17+
halfbrown = { version = "0.3", optional = true }
1818
float-cmp = "0.10"
19-
ordered-float = { version = "4", optional = true }
19+
ordered-float = { version = "5", optional = true }
2020
hashbrown = { version = "0.15", optional = true }
2121
abi_stable = { version = "0.11.0", optional = true, default-features = false }
2222

src/array.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub trait Array {
1818

1919
/// Iterates over the values paris
2020
#[must_use]
21-
fn iter<'i>(&'i self) -> Box<dyn Iterator<Item = &Self::Element> + 'i>;
21+
fn iter(&self) -> Box<dyn Iterator<Item = &Self::Element> + '_>;
2222

2323
/// Number of key/value pairs
2424
#[must_use]
@@ -69,7 +69,7 @@ where
6969
impl<T> Array for Vec<T> {
7070
type Element = T;
7171

72-
fn iter<'i>(&'i self) -> Box<dyn Iterator<Item = &T> + 'i> {
72+
fn iter(&self) -> Box<dyn Iterator<Item = &T> + '_> {
7373
Box::new(<[T]>::iter(self))
7474
}
7575

src/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::io::{self, Write};
22

3-
use crate::{array::Array, object::Object, TryTypeError, ValueType};
3+
use crate::{TryTypeError, ValueType, array::Array, object::Object};
44

55
/// Type information on a value
66
pub trait TypedValue {

src/derived.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{borrow::Borrow, hash::Hash};
22

3-
use crate::{array::Array, object::Object, AccessError, TryTypeError};
3+
use crate::{AccessError, TryTypeError, array::Array, object::Object};
44

55
/// `try_as_*` access to scalar value types
66
pub trait ValueTryAsScalar {
@@ -678,7 +678,6 @@ pub trait MutableValueArrayAccess<I> {
678678
/// Access to a value as an array with error handling
679679
pub trait ValueArrayTryAccess {
680680
/// The target for nested lookups
681-
682681
type Target: ?Sized;
683682
/// Tries to get a value based on n index, returns a type error if the
684683
/// current value isn't an Array, returns `None` if the index is out of bounds
@@ -705,7 +704,6 @@ pub trait ValueTryIntoArray {
705704
/// Tries to turn the value into it's array representation
706705
/// # Errors
707706
/// if the requested type doesn't match the actual type
708-
709707
fn try_into_array(self) -> Result<Self::Array, TryTypeError>;
710708
}
711709
/// A trait that specifies how to turn the Value `into` it's sub types with error handling

src/generator.rs

Lines changed: 71 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,13 @@ pub trait BaseGenerator {
128128
#[inline]
129129
fn write_string_content(&mut self, string: &str) -> io::Result<()> {
130130
let mut string = string.as_bytes();
131-
132131
unsafe {
133132
// Looking at the table above the lower 5 bits are entirely
134133
// quote characters that gives us a bitmask of 0x1f for that
135134
// region, only quote (`"`) and backslash (`\`) are not in
136135
// this range.
137136
stry!(self.write_str_simd(&mut string));
138137
}
139-
140138
write_string_rust(self.get_writer(), &mut string)
141139
}
142140

@@ -238,7 +236,9 @@ pub trait BaseGenerator {
238236
/// # Errors
239237
/// if the write fails
240238
unsafe fn write_str_simd(&mut self, string: &mut &[u8]) -> io::Result<()> {
241-
self.write_simple_string(std::str::from_utf8_unchecked(string))
239+
write_string_rust(self.get_writer(), string)?;
240+
*string = &string[string.len()..];
241+
Ok(())
242242
}
243243

244244
#[cfg(target_arch = "aarch64")]
@@ -257,57 +257,63 @@ pub trait BaseGenerator {
257257

258258
#[inline]
259259
unsafe fn bit_mask() -> uint8x16_t {
260-
mem::transmute([
261-
0x01_u8, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x4, 0x8, 0x10, 0x20,
262-
0x40, 0x80,
263-
])
260+
unsafe {
261+
mem::transmute([
262+
0x01_u8, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x4, 0x8, 0x10,
263+
0x20, 0x40, 0x80,
264+
])
265+
}
264266
}
265267

266268
#[inline]
267269
unsafe fn neon_movemask(input: uint8x16_t) -> u16 {
268-
let simd_input: uint8x16_t = vandq_u8(input, bit_mask());
269-
let tmp: uint8x16_t = vpaddq_u8(simd_input, simd_input);
270-
let tmp = vpaddq_u8(tmp, tmp);
271-
let tmp = vpaddq_u8(tmp, tmp);
270+
unsafe {
271+
let simd_input: uint8x16_t = vandq_u8(input, bit_mask());
272+
let tmp: uint8x16_t = vpaddq_u8(simd_input, simd_input);
273+
let tmp = vpaddq_u8(tmp, tmp);
274+
let tmp = vpaddq_u8(tmp, tmp);
272275

273-
vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0)
276+
vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0)
277+
}
274278
}
275279

276280
let writer = self.get_writer();
277281
// The case where we have a 16+ byte block
278282
// we repeate the same logic as above but with
279283
// only 16 bytes
280284
let mut idx = 0;
281-
let zero = vdupq_n_u8(0);
282-
let lower_quote_range = vdupq_n_u8(0x1F);
283-
let quote = vdupq_n_u8(b'"');
284-
let backslash = vdupq_n_u8(b'\\');
285-
while string.len() - idx > 16 {
286-
// Load 16 bytes of data;
287-
let data: uint8x16_t = vld1q_u8(string.as_ptr().add(idx));
288-
// Test the data against being backslash and quote.
289-
let bs_or_quote = vorrq_u8(vceqq_u8(data, backslash), vceqq_u8(data, quote));
290-
// Now mask the data with the quote range (0x1F).
291-
let in_quote_range = vandq_u8(data, lower_quote_range);
292-
// then test of the data is unchanged. aka: xor it with the
293-
// Any field that was inside the quote range it will be zero
294-
// now.
295-
let is_unchanged = veorq_u8(data, in_quote_range);
296-
let in_range = vceqq_u8(is_unchanged, zero);
297-
let quote_bits = neon_movemask(vorrq_u8(bs_or_quote, in_range));
298-
if quote_bits == 0 {
299-
idx += 16;
300-
} else {
301-
let quote_dist = quote_bits.trailing_zeros() as usize;
302-
stry!(writer.write_all(&string[0..idx + quote_dist]));
303-
let ch = string[idx + quote_dist];
304-
match ESCAPED[ch as usize] {
305-
b'u' => stry!(u_encode(writer, ch)),
306-
escape => stry!(writer.write_all(&[b'\\', escape])),
285+
unsafe {
286+
let zero = vdupq_n_u8(0);
287+
let lower_quote_range = vdupq_n_u8(0x1F);
288+
let quote = vdupq_n_u8(b'"');
289+
let backslash = vdupq_n_u8(b'\\');
290+
while string.len() - idx > 16 {
291+
// Load 16 bytes of data;
292+
let data: uint8x16_t = vld1q_u8(string.as_ptr().add(idx));
293+
// Test the data against being backslash and quote.
294+
let bs_or_quote = vorrq_u8(vceqq_u8(data, backslash), vceqq_u8(data, quote));
295+
// Now mask the data with the quote range (0x1F).
296+
let in_quote_range = vandq_u8(data, lower_quote_range);
297+
// then test of the data is unchanged. aka: xor it with the
298+
// Any field that was inside the quote range it will be zero
299+
// now.
300+
let is_unchanged = veorq_u8(data, in_quote_range);
301+
let in_range = vceqq_u8(is_unchanged, zero);
302+
let quote_bits = neon_movemask(vorrq_u8(bs_or_quote, in_range));
303+
if quote_bits == 0 {
304+
idx += 16;
305+
} else {
306+
let quote_dist = quote_bits.trailing_zeros() as usize;
307+
stry!(writer.write_all(&string[0..idx + quote_dist]));
308+
let ch = string[idx + quote_dist];
309+
match ESCAPED[ch as usize] {
310+
b'u' => stry!(u_encode(writer, ch)),
311+
escape => stry!(writer.write_all(&[b'\\', escape])),
312+
}
313+
314+
*string = &string[idx + quote_dist + 1..];
315+
idx = 0;
307316
}
308-
309-
*string = &string[idx + quote_dist + 1..];
310-
idx = 0;
311317
}
312318
}
313319
stry!(writer.write_all(&string[0..idx]));
@@ -414,11 +420,9 @@ where
414420
write_str_simd_sse42(writer, string)
415421
} else {
416422
#[cfg(not(feature = "portable"))]
417-
let r = write_string_rust(writer, string);
423+
return write_string_rust(writer, string);
418424
#[cfg(feature = "portable")]
419-
let r = write_str_simd_portable(writer, string);
420-
421-
r
425+
return write_str_simd_portable(writer, string);
422426
}
423427
}
424428
#[inline]
@@ -468,7 +472,7 @@ unsafe fn write_str_simd_portable<W>(writer: &mut W, string: &mut &[u8]) -> io::
468472
where
469473
W: Write,
470474
{
471-
use std::simd::{u8x32, SimdPartialEq, ToBitMask};
475+
use std::simd::{SimdPartialEq, ToBitMask, u8x32};
472476

473477
let mut idx = 0;
474478
let zero = u8x32::splat(0);
@@ -781,7 +785,7 @@ where
781785
}
782786
}
783787

784-
impl<'w, W> BaseGenerator for WriterGenerator<'w, W>
788+
impl<W> BaseGenerator for WriterGenerator<'_, W>
785789
where
786790
W: Write,
787791
{
@@ -799,7 +803,6 @@ where
799803
}
800804

801805
/// Pretty Writer Generator
802-
803806
pub struct PrettyWriterGenerator<'w, W>
804807
where
805808
W: 'w + Write,
@@ -823,7 +826,7 @@ where
823826
}
824827
}
825828

826-
impl<'w, W> BaseGenerator for PrettyWriterGenerator<'w, W>
829+
impl<W> BaseGenerator for PrettyWriterGenerator<'_, W>
827830
where
828831
W: Write,
829832
{
@@ -873,3 +876,22 @@ pub(crate) fn extend_from_slice(dst: &mut Vec<u8>, src: &[u8]) {
873876
dst.set_len(dst_len + src_len);
874877
}
875878
}
879+
880+
#[cfg(test)]
881+
mod tests {
882+
883+
#[test]
884+
fn test_write_string_rust() {
885+
let mut writer = Vec::new();
886+
let mut string = "Hello, World!".as_bytes();
887+
super::write_string_rust(&mut writer, &mut string).expect("failed to write string");
888+
assert_eq!(writer, "Hello, World!".as_bytes());
889+
}
890+
#[test]
891+
fn test_write_string_rust2() {
892+
let mut writer = Vec::new();
893+
let mut string = "Hello, \"World!\"".as_bytes();
894+
super::write_string_rust(&mut writer, &mut string).expect("failed to write string");
895+
assert_eq!(writer, "Hello, \\\"World!\\\"".as_bytes());
896+
}
897+
}

src/impls.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{borrow::Borrow, hash::Hash};
22

33
use crate::{
4+
AccessError, ExtendedValueType, TryTypeError, ValueType,
45
array::{self, ArrayMut, Indexed, IndexedMut},
56
base::{TypedValue, ValueAsScalar, ValueIntoString, ValueTryAsArrayMut, ValueTryAsMutObject},
67
derived::{
@@ -16,7 +17,6 @@ use crate::{
1617
ValueAsArray, ValueAsMutArray, ValueAsMutObject, ValueAsObject, ValueIntoArray,
1718
ValueIntoObject,
1819
},
19-
AccessError, ExtendedValueType, TryTypeError, ValueType,
2020
};
2121

2222
impl<T> ValueTryIntoString for T

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ compile_error!(
2424
);
2525

2626
#[cfg(all(feature = "c-abi", feature = "ordered-float"))]
27-
compile_error!("Combining the features `c-abi` and `ordered-float` is impossible because ordered_float::OrderedFloat does not implement `StableAbi`");
27+
compile_error!(
28+
"Combining the features `c-abi` and `ordered-float` is impossible because ordered_float::OrderedFloat does not implement `StableAbi`"
29+
);
2830

2931
use std::borrow::Cow;
3032
use std::fmt;

src/node.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::base::{TypedValue, ValueAsScalar};
22

3-
use super::{fmt, ValueType};
3+
use super::{ValueType, fmt};
44
use std::convert::TryFrom;
55
use std::ops::{Index, IndexMut};
66

0 commit comments

Comments
 (0)