Skip to content

Commit cd20296

Browse files
committed
Correctly report numeric overflow and clarify error semantics
Fixes a bug where ReadErrorReason::NotEnoughPrecision was never constructed. NotEnoughPrecision renamed to NumericValueOverflow for clearer semantics. Replaced magic decimal threshold with equivalent hex literal (0x80000000000000) for better readability.
1 parent b581432 commit cd20296

6 files changed

Lines changed: 14 additions & 13 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ name = "shvproto"
55
description = "Rust implementation of the SHV protocol"
66
license = "MIT"
77
repository = "https://github.com/silicon-heaven/libshvproto-rs"
8-
version = "5.0.1"
8+
version = "6.0.0"
99
edition = "2024"
1010

1111
[dependencies]

src/bin/cp2cp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ fn print_option<T: Display>(n: Option<T>) {
6363
fn exit_with_result_and_code(result: &ChainPackRpcBlockResult, error: Option<ReadErrorReason>) -> ! {
6464
let exit_code = error.map_or(CODE_SUCCESS, |error| match error {
6565
ReadErrorReason::UnexpectedEndOfStream => CODE_NOT_ENOUGH_DATA,
66-
ReadErrorReason::NotEnoughPrecision => CODE_READ_ERROR,
66+
ReadErrorReason::NumericValueOverflow => CODE_READ_ERROR,
6767
ReadErrorReason::InvalidCharacter => {
6868
eprintln!("Parse input error: {error:?}");
6969
CODE_READ_ERROR

src/cpon.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ mod test
572572
use std::collections::BTreeMap;
573573
use chrono::{Duration, FixedOffset, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
574574
use crate::cpon::CponReader;
575-
use crate::reader::Reader;
575+
use crate::reader::{ReadErrorReason, Reader};
576576
use crate::rpcvalue::Map;
577577
#[test]
578578
fn test_read() {
@@ -604,7 +604,7 @@ mod test
604604
test_cpon_round_trip("1000000.", Decimal::new(1_000_000, 0));
605605
test_cpon_round_trip("50.03138741402532", Decimal::new(5_003_138_741_402_532, -14));
606606
// We do not support such high precision.
607-
assert!(RpcValue::from_cpon("36.028797018963968").is_err());
607+
assert!(RpcValue::from_cpon("36.028797018963968").is_err_and(|err| matches!(err.reason, ReadErrorReason::NumericValueOverflow)));
608608
assert_eq!(RpcValue::from_cpon(r#""foo""#).unwrap().as_str(), "foo");
609609
assert_eq!(RpcValue::from_cpon(r#""ěščřžýáí""#).unwrap().as_str(), "ěščřžýáí");
610610
assert_eq!(RpcValue::from_cpon("b\"foo\tbar\nbaz\"").unwrap().as_blob(), b"foo\tbar\nbaz");
@@ -706,8 +706,8 @@ mod test
706706
assert_eq!(RpcValue::from_cpon("-0x8000000000000000").unwrap().as_int(), i64::MIN);
707707
assert_eq!(RpcValue::from_cpon("-0x8000000000000001").unwrap().as_int(), i64::MIN);
708708

709-
assert!(RpcValue::from_cpon("1.23456789012345678901234567890123456789012345678901234567890").is_err());
710-
assert!(RpcValue::from_cpon("12345678901234567890123456789012345678901234567890123456.7890").is_err());
711-
assert!(RpcValue::from_cpon("123456789012345678901234567890123456789012345678901234567890.").is_err());
709+
assert!(RpcValue::from_cpon("1.23456789012345678901234567890123456789012345678901234567890").is_err_and(|err| matches!(err.reason, ReadErrorReason::NumericValueOverflow)));
710+
assert!(RpcValue::from_cpon("12345678901234567890123456789012345678901234567890123456.7890").is_err_and(|err| matches!(err.reason, ReadErrorReason::NumericValueOverflow)));
711+
assert!(RpcValue::from_cpon("123456789012345678901234567890123456789012345678901234567890.").is_err_and(|err| matches!(err.reason, ReadErrorReason::NumericValueOverflow)));
712712
}
713713
}

src/json.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ impl<R> Reader for JsonReader<'_, R>
415415
mod test
416416
{
417417
use crate::Map;
418+
use crate::reader::ReadErrorReason;
418419
use chrono::{Duration, FixedOffset, LocalResult};
419420
use crate::json::{TAG_META, TAG_TYPE};
420421
use crate::{Decimal, IMap, RpcValue};
@@ -567,8 +568,8 @@ mod test
567568
assert_eq!(RpcValue::from_json("-0x8000000000000000").unwrap().as_int(), i64::MIN);
568569
assert_eq!(RpcValue::from_json("-0x8000000000000001").unwrap().as_int(), i64::MIN);
569570

570-
assert!(RpcValue::from_json("1.23456789012345678901234567890123456789012345678901234567890").is_err());
571-
assert!(RpcValue::from_json("12345678901234567890123456789012345678901234567890123456.7890").is_err());
572-
assert!(RpcValue::from_json("123456789012345678901234567890123456789012345678901234567890.").is_err());
571+
assert!(RpcValue::from_json("1.23456789012345678901234567890123456789012345678901234567890").is_err_and(|err| matches!(err.reason, ReadErrorReason::NumericValueOverflow)));
572+
assert!(RpcValue::from_json("12345678901234567890123456789012345678901234567890123456.7890").is_err_and(|err| matches!(err.reason, ReadErrorReason::NumericValueOverflow)));
573+
assert!(RpcValue::from_json("123456789012345678901234567890123456789012345678901234567890.").is_err_and(|err| matches!(err.reason, ReadErrorReason::NumericValueOverflow)));
573574
}
574575
}

src/reader.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::rpcvalue::Value;
66
pub enum ReadErrorReason {
77
UnexpectedEndOfStream,
88
InvalidCharacter,
9-
NotEnoughPrecision,
9+
NumericValueOverflow,
1010
}
1111
#[derive(Debug)]
1212
pub struct ReadError {

src/textrdwr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ pub trait TextReader : Reader {
233233
let ReadInt { value, digit_cnt, is_overflow, .. } = self.read_int(mantissa, true)?;
234234
decimal_overflow = decimal_overflow || is_overflow;
235235
mantissa = value;
236-
if mantissa >= 36_028_797_018_963_968 {
236+
if mantissa >= 0x80_0000_0000_0000 {
237237
decimal_overflow = true;
238238
}
239239
dec_cnt = i64::from(digit_cnt);
@@ -260,7 +260,7 @@ pub trait TextReader : Reader {
260260
let mantissa = if is_negative { -mantissa } else { mantissa };
261261
if is_decimal {
262262
if decimal_overflow {
263-
return Err(self.make_error("Not enough precision to read the Decimal", ReadErrorReason::InvalidCharacter))
263+
return Err(self.make_error("Not enough precision to read the Decimal", ReadErrorReason::NumericValueOverflow))
264264
}
265265
#[expect(clippy::cast_possible_truncation, reason = "We hope that the new exponent is not big enough to truncate")]
266266
return Ok(Value::from(Decimal::new(mantissa, (exponent - dec_cnt) as i8)))

0 commit comments

Comments
 (0)