diff --git a/Cargo.lock b/Cargo.lock
index 5c4675a7..cb57b652 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -40,9 +40,9 @@ checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
[[package]]
name = "arrayvec"
-version = "0.7.4"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "asn1-rs"
@@ -152,9 +152,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
-version = "1.1.10"
+version = "1.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292"
+checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48"
+dependencies = [
+ "shlex",
+]
[[package]]
name = "cfg-if"
@@ -200,9 +203,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.15"
+version = "4.5.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc"
+checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
dependencies = [
"clap_builder",
]
@@ -339,7 +342,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.74",
+ "syn 2.0.75",
]
[[package]]
@@ -395,9 +398,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
-version = "0.3.9"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
[[package]]
name = "hex"
@@ -413,9 +416,9 @@ checksum = "71a816c97c42258aa5834d07590b718b4c9a598944cd39a52dc25b351185d678"
[[package]]
name = "is-terminal"
-version = "0.4.12"
+version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
+checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
dependencies = [
"hermit-abi",
"libc",
@@ -439,9 +442,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "js-sys"
-version = "0.3.69"
+version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
+checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
dependencies = [
"wasm-bindgen",
]
@@ -480,9 +483,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
-version = "0.2.155"
+version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
[[package]]
name = "log"
@@ -870,29 +873,29 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.206"
+version = "1.0.208"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b3e4cd94123dd520a128bcd11e34d9e9e423e7e3e50425cb1b4b1e3549d0284"
+checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.206"
+version = "1.0.208"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fabfb6138d2383ea8208cf98ccf69cdfb1aff4088460681d84189aa259762f97"
+checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.74",
+ "syn 2.0.75",
]
[[package]]
name = "serde_json"
-version = "1.0.124"
+version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d"
+checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed"
dependencies = [
"itoa",
"memchr",
@@ -900,6 +903,12 @@ dependencies = [
"serde",
]
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
[[package]]
name = "snafu"
version = "0.7.5"
@@ -936,9 +945,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.74"
+version = "2.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7"
+checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
dependencies = [
"proc-macro2",
"quote",
@@ -980,7 +989,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.74",
+ "syn 2.0.75",
]
[[package]]
@@ -1047,9 +1056,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-xid"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
+checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a"
[[package]]
name = "uuid"
@@ -1078,34 +1087,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
-version = "0.2.92"
+version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
+checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
dependencies = [
"cfg-if",
+ "once_cell",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.92"
+version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
+checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
- "syn 2.0.74",
+ "syn 2.0.75",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.92"
+version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
+checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1113,28 +1123,28 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.92"
+version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
+checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.74",
+ "syn 2.0.75",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.92"
+version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
+checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
[[package]]
name = "web-sys"
-version = "0.3.69"
+version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
+checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
dependencies = [
"js-sys",
"wasm-bindgen",
diff --git a/Cargo.toml b/Cargo.toml
index 902731de..2e7a2370 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -45,6 +45,12 @@ name = "iai"
path = "benches/iai.rs"
harness = false
+[[bench]]
+name = "criterion_integer"
+path = "benches/integer.rs"
+harness = false
+test = true
+
[dependencies]
nom = { version = "7.1.3", default-features = false, features = ["alloc"] }
num-bigint = { version = "0.4.3", default-features = false }
@@ -59,11 +65,11 @@ nom-bitvec = { package = "bitvec-nom2", version = "0.2.0" }
arrayvec = { version = "0.7.4", default-features = false }
either = { version = "1.9.0", default-features = false }
once_cell = { version = "1.18.0", default-features = false, features = [
- "race",
- "alloc",
+ "race",
+ "alloc",
] }
num-integer = { version = "0.1.45", default-features = false, features = [
- "i128",
+ "i128",
] }
jzon = { version = "0.12.5", optional = true }
diff --git a/README.md b/README.md
index c7bd4fa8..d941d4c8 100644
--- a/README.md
+++ b/README.md
@@ -243,7 +243,7 @@ type TestTypeB = bool;
type TestTypeA = TestTypeB;
```
```rust
-// or
+// or
use rasn::prelude::*;
#[derive(AsnType, Decode, Encode)]
@@ -621,11 +621,11 @@ Test-type-a ::= CHOICE {
raisin OCTET STRING
}
-Test-type-b ::= CHOICE {
- juice INTEGER (0..3,...),
+Test-type-b ::= CHOICE {
+ juice INTEGER (0..3,...),
wine OCTET STRING,
...,
- grappa INTEGER
+ grappa INTEGER
}
```
@@ -663,8 +663,8 @@ enum TestTypeB {
```asn
-Test-type-a ::= SEQUENCE {
- juice INTEGER (0..3,...),
+Test-type-a ::= SEQUENCE {
+ juice INTEGER (0..3,...),
wine OCTET STRING,
...,
grappa INTEGER OPTIONAL,
@@ -699,7 +699,7 @@ struct TestTypeA {
|
```asn
-Test-type-a ::= SET {
+Test-type-a ::= SET {
seed NULL,
grape BOOLEAN,
raisin INTEGER
@@ -711,7 +711,7 @@ Test-type-a ::= SET {
```rust
use rasn::prelude::*;
-/// the SET declaration is basically identical to a SEQUENCE declaration,
+/// the SET declaration is basically identical to a SEQUENCE declaration,
/// except for the `set` annotation
#[derive(AsnType, Decode, Encode)]
#[rasn(set, automatic_tags)]
@@ -730,7 +730,7 @@ struct TestTypeA {
|
```asn
-Test-type-a ::= SEQUENCE {
+Test-type-a ::= SEQUENCE {
notQuiteRustCase INTEGER
}
```
@@ -757,7 +757,7 @@ struct TestTypeA {
|
```asn
-Test-type-a ::= SEQUENCE {
+Test-type-a ::= SEQUENCE {
seed BOOLEAN DEFAULT TRUE,
grape INTEGER OPTIONAL,
raisin INTEGER DEFAULT 1
@@ -773,7 +773,7 @@ use rasn::prelude::*;
#[derive(AsnType, Decode, Encode)]
#[rasn(automatic_tags)]
struct TestTypeA {
- #[rasn(default = "default_seed")]
+ #[rasn(default = "default_seed")]
seed: bool,
grape: Option,
#[rasn(default = "default_raisin")]
diff --git a/benches/integer.rs b/benches/integer.rs
new file mode 100644
index 00000000..1c7d8b0e
--- /dev/null
+++ b/benches/integer.rs
@@ -0,0 +1,143 @@
+// Based on https://github.com/dudycz/asn1_codecs_bench under Apache License Version 2.0 License
+//
+// Modifications:
+// Adds other rasn codecs to the benchmark
+
+use criterion::{criterion_group, criterion_main, Criterion};
+use rasn::{ber, oer, uper};
+
+#[allow(non_camel_case_types, non_snake_case, non_upper_case_globals, unused)]
+pub mod world3d {
+ extern crate alloc;
+ use core::borrow::Borrow;
+ use rasn::prelude::*;
+ #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq)]
+ #[rasn(automatic_tags)]
+ pub struct Color {
+ #[rasn(value("0..=255"))]
+ pub r: u8,
+ #[rasn(value("0..=255"))]
+ pub g: u8,
+ #[rasn(value("0..=255"))]
+ pub b: u8,
+ #[rasn(value("0..=65335"))]
+ pub a: u16,
+ }
+ impl Color {
+ pub fn new(r: u8, g: u8, b: u8, a: u16) -> Self {
+ Self { r, g, b, a }
+ }
+ }
+ #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq)]
+ #[rasn(automatic_tags)]
+ pub struct Column {
+ #[rasn(size("10"))]
+ pub elements: SequenceOf,
+ }
+ impl Column {
+ pub fn new(elements: SequenceOf) -> Self {
+ Self { elements }
+ }
+ }
+ #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq)]
+ #[rasn(automatic_tags)]
+ pub struct Plane {
+ #[rasn(size("10"))]
+ pub rows: SequenceOf,
+ }
+ impl Plane {
+ pub fn new(rows: SequenceOf) -> Self {
+ Self { rows }
+ }
+ }
+ #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq)]
+ #[rasn(automatic_tags)]
+ pub struct World {
+ #[rasn(size("10"))]
+ pub depth: SequenceOf,
+ }
+ impl World {
+ pub fn new(depth: SequenceOf) -> Self {
+ Self { depth }
+ }
+ }
+}
+
+pub fn build_sample_rasn() -> world3d::World {
+ use world3d::*;
+ let color = Color::new(42, 128, 77, 12312);
+ let elements = (0..10).map(|_| color.clone()).collect::>();
+ let column = Column { elements };
+ let rows = (0..10).map(|_| column.clone()).collect::>();
+ let plane = Plane { rows };
+ let depth = (0..10).map(|_| plane.clone()).collect::>();
+
+ World { depth }
+}
+
+fn uper_rasn_enc(c: &mut Criterion) {
+ c.bench_function("RASN/encode UPER - sample.asn", |b| {
+ b.iter(|| {
+ let w = build_sample_rasn();
+ let _ = uper::encode(&w).unwrap();
+ })
+ });
+}
+fn oer_rasn_enc(c: &mut Criterion) {
+ c.bench_function("RASN/encode OER - sample.asn", |b| {
+ b.iter(|| {
+ let w = build_sample_rasn();
+ let _ = oer::encode(&w).unwrap();
+ })
+ });
+}
+fn ber_rasn_enc(c: &mut Criterion) {
+ c.bench_function("RASN/encode BER - sample.asn", |b| {
+ b.iter(|| {
+ let w = build_sample_rasn();
+ let _ = ber::encode(&w).unwrap();
+ })
+ });
+}
+
+fn uper_rasn_dec(c: &mut Criterion) {
+ let w = build_sample_rasn();
+ let encoded = uper::encode(&w).unwrap();
+
+ c.bench_function("RASN/decode UPER - sample.asn", |b| {
+ b.iter(|| {
+ let _ = uper::decode::(&encoded).unwrap();
+ })
+ });
+}
+fn oer_rasn_dec(c: &mut Criterion) {
+ let w = build_sample_rasn();
+ let encoded = oer::encode(&w).unwrap();
+
+ c.bench_function("RASN/decode OER - sample.asn", |b| {
+ b.iter(|| {
+ let _ = oer::decode::(&encoded).unwrap();
+ })
+ });
+}
+fn ber_rasn_dec(c: &mut Criterion) {
+ let w = build_sample_rasn();
+ let encoded = ber::encode(&w).unwrap();
+
+ c.bench_function("RASN/decode BER - sample.asn", |b| {
+ b.iter(|| {
+ let _ = ber::decode::(&encoded).unwrap();
+ })
+ });
+}
+
+criterion_group!(
+ benches,
+ uper_rasn_enc,
+ uper_rasn_dec,
+ oer_rasn_enc,
+ oer_rasn_dec,
+ ber_rasn_enc,
+ ber_rasn_dec
+);
+criterion_main!(benches);
diff --git a/src/ber/enc.rs b/src/ber/enc.rs
index 25956959..b2f2e53d 100644
--- a/src/ber/enc.rs
+++ b/src/ber/enc.rs
@@ -11,7 +11,7 @@ use crate::{
types::{
self,
oid::{MAX_OID_FIRST_OCTET, MAX_OID_SECOND_OCTET},
- Constraints, Enumerated, Tag,
+ Constraints, Enumerated, IntegerType, Tag,
},
Codec, Encode,
};
@@ -377,16 +377,17 @@ impl crate::Encoder for Encoder {
value: &E,
) -> Result {
let value = E::discriminant(value);
- self.encode_integer(tag, <_>::default(), &value.into())
+ self.encode_integer(tag, <_>::default(), &value)
}
- fn encode_integer(
+ fn encode_integer(
&mut self,
tag: Tag,
_constraints: Constraints,
- value: &num_bigint::BigInt,
+ value: &I,
) -> Result {
- self.encode_primitive(tag, &value.to_signed_bytes_be());
+ let (bytes, needed) = value.to_signed_bytes_be();
+ self.encode_primitive(tag, &bytes.as_ref()[..needed]);
Ok(())
}
diff --git a/src/bits.rs b/src/bits.rs
index f7ee9af4..124a19b1 100644
--- a/src/bits.rs
+++ b/src/bits.rs
@@ -1,9 +1,7 @@
//! Module for different bit modification functions which are used in the library.
-use core::cmp::Ordering;
-
use alloc::vec::Vec;
-use num_traits::{Signed, Zero};
+use core::cmp::Ordering;
pub(crate) fn range_from_len(bit_length: u32) -> i128 {
2i128.pow(bit_length) - 1
@@ -34,13 +32,3 @@ pub(crate) fn octet_string_ascending(a: &Vec, b: &Vec) -> Ordering {
}
a.len().cmp(&b.len())
}
-
-pub fn integer_to_bytes(value: &crate::prelude::Integer, signed: bool) -> Option> {
- if signed {
- Some(value.to_signed_bytes_be())
- } else if !signed && (value.is_positive() || value.is_zero()) {
- Some(value.to_biguint()?.to_bytes_be())
- } else {
- None
- }
-}
diff --git a/src/de.rs b/src/de.rs
index faacf5ce..61ba5478 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -1,6 +1,7 @@
//! Generic ASN.1 decoding framework.
use alloc::{boxed::Box, vec::Vec};
+use num_bigint::BigInt;
use crate::error::DecodeError;
use crate::types::{self, AsnType, Constraints, Enumerated, Tag};
@@ -396,12 +397,16 @@ impl_integers! {
i16,
i32,
i64,
+ i128,
isize,
u8,
u16,
u32,
u64,
+ // TODO cannot support u128 as it is constrained type by default and current constraints uses i128 for bounds
+ // u128,
usize,
+ BigInt
}
impl Decode for types::ConstrainedInteger {
@@ -422,7 +427,7 @@ impl Decode for types::Integer {
tag: Tag,
constraints: Constraints,
) -> Result {
- decoder.decode_integer(tag, constraints)
+ decoder.decode_integer::(tag, constraints)
}
}
diff --git a/src/enc.rs b/src/enc.rs
index c47c7be7..07bfe3b0 100644
--- a/src/enc.rs
+++ b/src/enc.rs
@@ -1,7 +1,8 @@
//! Generic ASN.1 encoding framework.
-use crate::types::{self, AsnType, Constraints, Enumerated, Tag};
+use crate::types::{self, AsnType, Constraints, Enumerated, IntegerType, Tag};
+use num_bigint::BigInt;
pub use rasn_derive::Encode;
/// A **data type** that can be encoded to a ASN.1 data format.
@@ -80,11 +81,11 @@ pub trait Encoder {
) -> Result;
/// Encode a `INTEGER` value.
- fn encode_integer(
+ fn encode_integer(
&mut self,
tag: Tag,
constraints: Constraints,
- value: &num_bigint::BigInt,
+ value: &I,
) -> Result;
/// Encode a `NULL` value.
@@ -461,7 +462,7 @@ macro_rules! impl_integers {
encoder.encode_integer(
tag,
constraints,
- &(*self).into()
+ self
).map(drop)
}
}
@@ -474,15 +475,18 @@ impl_integers! {
i16,
i32,
i64,
+ i128,
isize,
u8,
u16,
u32,
u64,
+ // TODO cannot support u128 as it is constrained type by default and current constraints uses i128 for bounds
+ u128,
usize
}
-impl Encode for types::ConstrainedInteger {
+impl Encode for BigInt {
fn encode_with_tag_and_constraints(
&self,
encoder: &mut E,
@@ -493,6 +497,17 @@ impl Encode for types::ConstrainedInteger Encode for types::ConstrainedInteger {
+ fn encode_with_tag_and_constraints(
+ &self,
+ encoder: &mut E,
+ tag: Tag,
+ constraints: Constraints,
+ ) -> Result<(), E::Error> {
+ encoder.encode_integer(tag, constraints, &**self).map(drop)
+ }
+}
+
impl Encode for types::Integer {
fn encode_with_tag_and_constraints(
&self,
diff --git a/src/error/decode.rs b/src/error/decode.rs
index c468fb86..1486e59c 100644
--- a/src/error/decode.rs
+++ b/src/error/decode.rs
@@ -11,8 +11,9 @@ use snafu::Snafu;
use snafu::{Backtrace, GenerateImplicitData};
use crate::de::Error;
-use crate::types::{constraints::Bounded, variants::Variants, Integer, Tag};
+use crate::types::{constraints::Bounded, variants::Variants, Tag};
use crate::Codec;
+use num_bigint::BigInt;
/// Variants for every codec-specific `DecodeError` kind.
#[derive(Debug)]
@@ -172,7 +173,7 @@ impl DecodeError {
}
#[must_use]
pub fn value_constraint_not_satisfied(
- value: Integer,
+ value: BigInt,
expected: Bounded,
codec: Codec,
) -> Self {
@@ -267,7 +268,11 @@ impl DecodeError {
)
}
#[must_use]
- pub fn choice_index_exceeds_platform_width(needed: u32, present: u64, codec: Codec) -> Self {
+ pub fn choice_index_exceeds_platform_width(
+ needed: u32,
+ present: DecodeError,
+ codec: Codec,
+ ) -> Self {
Self::from_kind(
DecodeErrorKind::ChoiceIndexExceedsPlatformWidth { needed, present },
codec,
@@ -372,7 +377,7 @@ pub enum DecodeErrorKind {
#[snafu(display("Value constraint not satisfied: expected: {expected}; actual: {value}"))]
ValueConstraintNotSatisfied {
/// Actual value of the data
- value: Integer,
+ value: BigInt,
/// Expected value by the constraint
expected: Bounded,
},
@@ -401,8 +406,8 @@ pub enum DecodeErrorKind {
ChoiceIndexExceedsPlatformWidth {
/// Amount of bytes needed.
needed: u32,
- /// Amount of bytes needed.
- present: u64,
+ /// Inner error
+ present: DecodeError,
},
#[snafu(display("Custom: {}", msg))]
Custom {
diff --git a/src/error/encode.rs b/src/error/encode.rs
index d2560213..8fe8ffe2 100644
--- a/src/error/encode.rs
+++ b/src/error/encode.rs
@@ -1,5 +1,5 @@
-use crate::prelude::Integer;
use crate::types::constraints::{Bounded, Size};
+use num_bigint::BigInt;
use snafu::Snafu;
#[cfg(feature = "backtraces")]
use snafu::{Backtrace, GenerateImplicitData};
@@ -147,7 +147,7 @@ impl EncodeError {
}
#[must_use]
pub fn value_constraint_not_satisfied(
- value: Integer,
+ value: BigInt,
expected: &Bounded,
codec: crate::Codec,
) -> Self {
@@ -258,7 +258,7 @@ pub enum EncodeErrorKind {
#[snafu(display("Value constraint not satisfied: expected: {expected}; actual: {value}"))]
ValueConstraintNotSatisfied {
/// Actual value of the data
- value: Integer,
+ value: BigInt,
/// Expected value by the constraint
expected: Bounded,
},
@@ -322,7 +322,7 @@ pub enum JerEncodeErrorKind {
#[snafu(display("Exceeds supported integer range -2^63..2^63 ({:?}).", value))]
ExceedsSupportedIntSize {
/// value failed to encode
- value: num_bigint::BigInt,
+ value: BigInt,
},
#[snafu(display("Invalid character: {:?}", error))]
InvalidCharacter {
diff --git a/src/jer/enc.rs b/src/jer/enc.rs
index 9bfce7ae..ec5bae4a 100644
--- a/src/jer/enc.rs
+++ b/src/jer/enc.rs
@@ -5,7 +5,7 @@ use jzon::{object::Object, JsonValue};
use crate::{
enc::Error,
error::{EncodeError, JerEncodeErrorKind},
- types::{fields::Fields, variants},
+ types::{fields::Fields, variants, IntegerType},
};
pub struct Encoder {
@@ -131,19 +131,20 @@ impl crate::Encoder for Encoder {
))
}
- fn encode_integer(
+ fn encode_integer(
&mut self,
_t: crate::Tag,
_c: crate::types::Constraints,
- value: &num_bigint::BigInt,
+ value: &I,
) -> Result {
- let as_i64: i64 =
- value
- .try_into()
- .map_err(|_| JerEncodeErrorKind::ExceedsSupportedIntSize {
- value: value.clone(),
- })?;
- self.update_root_or_constructed(JsonValue::Number(as_i64.into()))
+ if let Some(as_i64) = value.to_i64() {
+ self.update_root_or_constructed(JsonValue::Number(as_i64.into()))
+ } else {
+ Err(JerEncodeErrorKind::ExceedsSupportedIntSize {
+ value: value.to_bigint().unwrap_or_default().into(),
+ }
+ .into())
+ }
}
fn encode_null(&mut self, _: crate::Tag) -> Result {
diff --git a/src/lib.rs b/src/lib.rs
index 4e92c54c..fbecb798 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -166,7 +166,7 @@ mod tests {
}
}
- codecs!(uper, aper);
+ codecs!(uper, aper, oer, coer, ber);
}
#[test]
@@ -204,20 +204,23 @@ mod tests {
i16,
i32,
i64,
+ // i128, TODO i128 does not work for UPER/APER
isize,
u8,
u16,
u32,
u64,
+ // TODO cannot support u128 as it is constrained type by default and current constraints uses i128 for bounds
+ // u128,
usize
}
#[test]
fn integer() {
- round_trip(&Integer::from(89));
- round_trip(&Integer::from(256));
- round_trip(&Integer::from(u64::MAX));
- round_trip(&Integer::from(i64::MIN));
+ round_trip(&89);
+ round_trip(&256);
+ round_trip(&u64::MAX);
+ round_trip(&i64::MIN);
}
#[test]
@@ -241,7 +244,7 @@ mod tests {
constraints: Constraints,
) -> Result<(), E::Error> {
encoder
- .encode_integer(tag, constraints, &self.0.into())
+ .encode_integer::(tag, constraints, &self.0.into())
.map(drop)
}
}
diff --git a/src/oer/de.rs b/src/oer/de.rs
index dacd8463..a636c796 100644
--- a/src/oer/de.rs
+++ b/src/oer/de.rs
@@ -248,21 +248,20 @@ impl<'input> Decoder<'input> {
if let Some(value) = constraints.value() {
ranges::determine_integer_size_and_sign(&value, self.input, |_, sign, octets| {
let integer = self.decode_integer_from_bytes::(sign, octets.map(usize::from))?;
-
// if the value is too large for a i128, the constraint isn't satisfied
- let constraint_integer = integer.clone().try_into().map_err(|_| {
- DecodeError::value_constraint_not_satisfied(
- integer.clone().into(),
- value.constraint.0,
- self.codec(),
- )
- })?;
-
- if value.constraint.contains(&constraint_integer) {
- Ok(integer)
+ if let Some(constraint_integer) = integer.to_i128() {
+ if value.constraint.contains(&constraint_integer) {
+ Ok(integer)
+ } else {
+ Err(DecodeError::value_constraint_not_satisfied(
+ integer.to_bigint().unwrap_or_default(),
+ value.constraint.0,
+ self.codec(),
+ ))
+ }
} else {
Err(DecodeError::value_constraint_not_satisfied(
- integer.into(),
+ integer.to_bigint().unwrap_or_default(),
value.constraint.0,
self.codec(),
))
diff --git a/src/oer/enc.rs b/src/oer/enc.rs
index 05bebf9a..ef891cd9 100644
--- a/src/oer/enc.rs
+++ b/src/oer/enc.rs
@@ -1,16 +1,16 @@
-use alloc::{string::ToString, vec::Vec};
+use alloc::vec::Vec;
use crate::oer::ranges;
use crate::prelude::{
Any, BitStr, BmpString, Choice, Constructed, Enumerated, GeneralString, GeneralizedTime,
Ia5String, NumericString, PrintableString, SetOf, TeletexString, UtcTime, VisibleString,
};
+use crate::types::IntegerType;
use crate::Codec;
use bitvec::prelude::*;
-use num_traits::{Signed, ToPrimitive};
+use num_traits::ToPrimitive;
-use crate::types;
-use crate::types::{fields::FieldPresence, BitString, Constraints, Integer};
+use crate::types::{fields::FieldPresence, BitString, Constraints, Date};
use crate::{Encode, Tag};
/// ITU-T X.696 (02/2021) version of (C)OER encoding
@@ -219,14 +219,8 @@ impl Encoder {
buffer: &mut Vec,
value: isize,
) -> Result<(), EncodeError> {
- let bytes =
- crate::bits::integer_to_bytes(&Integer::from(value), true).ok_or_else(|| {
- EncodeError::integer_type_conversion_failed(
- "Unconstrained enumerated index conversion failed".to_string(),
- self.codec(),
- )
- })?;
- let mut length = u8::try_from(bytes.len()).map_err(|err| {
+ let (bytes, needed) = value.to_signed_bytes_be();
+ let mut length = u8::try_from(needed).map_err(|err| {
EncodeError::integer_type_conversion_failed(
alloc::format!(
"Length of length conversion failed when encoding enumerated index.\
@@ -239,7 +233,7 @@ impl Encoder {
// There seems to be an error in standard. It states that enumerated index can be
// between –2^1015 and 2^1015 – 1, but then it limits the amount of subsequent bytes to 127
return Err(CoerEncodeErrorKind::TooLongValue {
- length: bytes.len() as u128,
+ length: needed as u128,
}
.into());
}
@@ -247,7 +241,7 @@ impl Encoder {
// It is always zero by default with u8 type when value being < 128
length |= 0b_1000_0000;
buffer.extend(&length.to_be_bytes());
- buffer.extend(&bytes);
+ buffer.extend(&bytes.as_ref()[..needed]);
Ok(())
}
/// Encode the length of the value to output.
@@ -255,20 +249,13 @@ impl Encoder {
///
/// COER tries to use the shortest possible encoding and avoids leading zeros.
fn encode_length(&mut self, buffer: &mut Vec, length: usize) -> Result<(), EncodeError> {
- let bytes =
- crate::bits::integer_to_bytes(&Integer::from(length), false).ok_or_else(|| {
- EncodeError::integer_type_conversion_failed(
- "For unknown reason, length conversion failed when encoding length".to_string(),
- self.codec(),
- )
- })?;
-
+ let (bytes, needed) = length.to_unsigned_bytes_be();
if length < 128 {
// First bit should be always zero when below 128: ITU-T X.696 8.6.4
- buffer.extend(&bytes);
+ buffer.extend(&bytes.as_ref()[..needed]);
return Ok(());
}
- let mut length_of_length = u8::try_from(bytes.len()).map_err(|err| {
+ let mut length_of_length = u8::try_from(needed).map_err(|err| {
EncodeError::integer_type_conversion_failed(
alloc::format!("Length of length conversion failed: {err}"),
self.codec(),
@@ -284,27 +271,27 @@ impl Encoder {
// It is always zero by default with u8 type when value being < 128
length_of_length |= 0b_1000_0000;
buffer.extend(&length_of_length.to_be_bytes());
- buffer.extend(&bytes);
+ buffer.extend(&bytes.as_ref()[..needed]);
Ok(())
}
/// Encode integer `value_to_enc` with length determinant
/// Either as signed or unsigned, set by `signed`
- fn encode_unconstrained_integer(
+ fn encode_unconstrained_integer(
&mut self,
- value_to_enc: &Integer,
+ buffer: &mut Vec,
+ value_to_enc: &I,
signed: bool,
- ) -> Result, EncodeError> {
- let mut buffer = Vec::new();
- let bytes = crate::bits::integer_to_bytes(value_to_enc, signed).ok_or_else(|| {
- EncodeError::integer_type_conversion_failed(
- "Negative integer value has been provided to be converted into unsigned bytes"
- .to_string(),
- self.codec(),
- )
- })?;
- self.encode_length(&mut buffer, bytes.len())?;
- buffer.extend(bytes);
- Ok(buffer)
+ ) -> Result<(), EncodeError> {
+ if signed {
+ let (bytes, needed) = value_to_enc.to_signed_bytes_be();
+ self.encode_length(buffer, needed)?;
+ buffer.extend(&bytes.as_ref()[..needed]);
+ } else {
+ let (bytes, needed) = value_to_enc.to_unsigned_bytes_be();
+ self.encode_length(buffer, needed)?;
+ buffer.extend(&bytes.as_ref()[..needed]);
+ };
+ Ok(())
}
/// Encode an integer value with constraints.
@@ -317,18 +304,18 @@ impl Encoder {
/// type with an extensible OER-visible constraint. Such a type is encoded as an integer type with no bounds.
///
/// If the Integer is not bound or outside of range, we encode with the smallest number of octets possible.
- fn encode_integer_with_constraints(
+ fn encode_integer_with_constraints(
&mut self,
tag: Tag,
constraints: &Constraints,
- value_to_enc: &Integer,
+ value_to_enc: &I,
) -> Result<(), EncodeError> {
- let mut buffer = Vec::new();
+ let mut buffer = Vec::with_capacity(8);
if let Some(value) = constraints.value() {
- if !value.constraint.0.bigint_contains(value_to_enc) && value.extensible.is_none() {
+ if !value.constraint.0.in_bound(value_to_enc) && value.extensible.is_none() {
return Err(EncodeError::value_constraint_not_satisfied(
- value_to_enc.clone(),
+ value_to_enc.to_bigint().unwrap_or_default(),
&value.constraint.0,
self.codec(),
));
@@ -337,23 +324,21 @@ impl Encoder {
&value,
value_to_enc,
|value_to_enc, sign, octets| -> Result<(), EncodeError> {
- let bytes: Vec;
if let Some(octets) = octets {
- bytes = self.encode_constrained_integer_with_padding(
+ self.encode_constrained_integer_with_padding(
+ &mut buffer,
usize::from(octets),
value_to_enc,
sign,
)?;
} else {
- bytes = self.encode_unconstrained_integer(value_to_enc, sign)?;
+ self.encode_unconstrained_integer(&mut buffer, value_to_enc, sign)?;
}
- buffer.extend(bytes);
Ok(())
},
)?;
} else {
- let bytes = self.encode_unconstrained_integer(value_to_enc, true)?;
- buffer.extend(bytes);
+ self.encode_unconstrained_integer(&mut buffer, value_to_enc, true)?;
}
self.extend(tag, buffer)?;
Ok(())
@@ -361,36 +346,40 @@ impl Encoder {
/// When range constraints are present, the integer is encoded as a fixed-size number.
/// This means that the zero padding is possible even with COER encoding.
- fn encode_constrained_integer_with_padding(
+ fn encode_constrained_integer_with_padding(
&mut self,
+ buffer: &mut Vec,
octets: usize,
- value: &Integer,
+ value: &I,
signed: bool,
- ) -> Result, EncodeError> {
+ ) -> Result<(), EncodeError> {
use core::cmp::Ordering;
if octets > 8 {
return Err(CoerEncodeErrorKind::InvalidConstrainedIntegerOctetSize.into());
}
+ let signed_ref;
+ let unsigned_ref;
+ let needed: usize;
let bytes = if signed {
- value.to_signed_bytes_be()
+ (signed_ref, needed) = value.to_signed_bytes_be();
+ signed_ref.as_ref()
} else {
- value.to_biguint().unwrap().to_bytes_be()
+ (unsigned_ref, needed) = value.to_unsigned_bytes_be();
+ unsigned_ref.as_ref()
};
- let mut buffer: Vec = Vec::new();
-
- match octets.cmp(&bytes.len()) {
+ match octets.cmp(&needed) {
Ordering::Greater => {
if signed && value.is_negative() {
// 2's complement
- buffer.extend(core::iter::repeat(0xff).take(octets - bytes.len()));
+ buffer.extend(core::iter::repeat(0xff).take(octets - needed));
} else {
- buffer.extend(core::iter::repeat(0x00).take(octets - bytes.len()));
+ buffer.extend(core::iter::repeat(0x00).take(octets - needed));
}
}
Ordering::Less => {
return Err(EncodeError::from_kind(
EncodeErrorKind::MoreBytesThanExpected {
- value: bytes.len(),
+ value: needed,
expected: octets,
},
self.codec(),
@@ -399,8 +388,8 @@ impl Encoder {
// As is
Ordering::Equal => {}
};
- buffer.extend(bytes);
- Ok(buffer)
+ buffer.extend(&bytes[..needed]);
+ Ok(())
}
fn check_fixed_size_constraint(
&self,
@@ -661,8 +650,7 @@ impl crate::Encoder for Encoder {
let number = value.discriminant();
let mut buffer = Vec::new();
if 0isize <= number && number <= i8::MAX.into() {
- let bytes = self.encode_constrained_integer_with_padding(1, &number.into(), false)?;
- buffer.extend(bytes);
+ self.encode_constrained_integer_with_padding(&mut buffer, 1, &number, false)?;
} else {
// Value is signed here as defined in section 11.4
// Long form but different from regular length determinant encoding
@@ -687,11 +675,11 @@ impl crate::Encoder for Encoder {
Ok(())
}
- fn encode_integer(
+ fn encode_integer(
&mut self,
tag: Tag,
constraints: Constraints,
- value: &Integer,
+ value: &I,
) -> Result {
self.set_bit(tag, true);
self.encode_integer_with_constraints(tag, &constraints, value)
@@ -829,7 +817,7 @@ impl crate::Encoder for Encoder {
)
}
- fn encode_date(&mut self, tag: Tag, value: &types::Date) -> Result {
+ fn encode_date(&mut self, tag: Tag, value: &Date) -> Result {
self.set_bit(tag, true);
self.encode_octet_string(
tag,
@@ -874,8 +862,7 @@ impl crate::Encoder for Encoder {
// It seems that constraints here are not C/OER visible? No mention in standard...
self.set_bit(tag, true);
let mut buffer = Vec::new();
- let value_len_bytes = self.encode_unconstrained_integer(&value.len().into(), false)?;
- buffer.extend(value_len_bytes);
+ self.encode_unconstrained_integer(&mut buffer, &value.len(), false)?;
for one in value {
let mut encoder = Self::new(self.options);
E::encode(one, &mut encoder)?;
@@ -1029,8 +1016,7 @@ mod tests {
let value_range = &[Constraint::Value(Extensible::new(Value::new(range_bound)))];
let consts = Constraints::new(value_range);
let mut encoder = Encoder::default();
- let result =
- encoder.encode_integer_with_constraints(Tag::INTEGER, &consts, &BigInt::from(244));
+ let result = encoder.encode_integer_with_constraints(Tag::INTEGER, &consts, &244);
assert!(result.is_ok());
let v = vec![244u8];
assert_eq!(encoder.output, v);
@@ -1066,7 +1052,7 @@ mod tests {
// Signed integer with byte length of 128
// Needs long form to represent
- let number = BigInt::from(256).pow(127) - 1;
+ let number: BigInt = BigInt::from(256).pow(127) - 1;
let result = encoder.encode_integer_with_constraints(Tag::INTEGER, &constraints, &number);
assert!(result.is_ok());
let vc = [
@@ -1086,6 +1072,7 @@ mod tests {
#[test]
fn test_choice() {
use crate as rasn;
+ use crate::types::Integer;
#[derive(AsnType, Decode, Debug, Encode, PartialEq)]
#[rasn(choice, automatic_tags)]
#[non_exhaustive]
diff --git a/src/per/de.rs b/src/per/de.rs
index b4d953c3..de25b493 100644
--- a/src/per/de.rs
+++ b/src/per/de.rs
@@ -2,6 +2,7 @@ use alloc::{collections::VecDeque, string::ToString, vec::Vec};
use bitvec::field::BitField;
use super::{FOURTY_EIGHT_K, SIXTEEN_K, SIXTY_FOUR_K, THIRTY_TWO_K};
+use crate::types::IntegerType;
use crate::{
de::Error as _,
types::{
@@ -345,15 +346,14 @@ impl<'input> Decoder<'input> {
Ok(boolean[0])
}
- fn parse_normally_small_integer(&mut self) -> Result {
+ fn parse_normally_small_integer(&mut self) -> Result {
let is_large = self.parse_one_bit()?;
let constraints = if is_large {
constraints::Value::new(constraints::Bounded::start_from(0)).into()
} else {
constraints::Value::new(constraints::Bounded::new(0, 63)).into()
};
-
- self.parse_integer(Constraints::new(&[constraints]))
+ self.parse_integer::(Constraints::new(&[constraints]))
}
fn parse_non_negative_binary_integer(
@@ -383,8 +383,7 @@ impl<'input> Decoder<'input> {
vec_bytes
}
};
-
- I::try_from_unsigned_bytes(&data.as_raw_slice(), self.codec())
+ I::try_from_unsigned_bytes(data.as_raw_slice(), self.codec())
}
fn parse_integer(&mut self, constraints: Constraints) -> Result {
@@ -399,22 +398,23 @@ impl<'input> Decoder<'input> {
const K64: i128 = SIXTY_FOUR_K as i128;
const OVER_K64: i128 = K64 + 1;
+ // Doing .map_error here causes 5% performance regression for unknown reason
+ // It would make code cleaner though
+ let minimum: I = match value_constraint.constraint.minimum().try_into() {
+ Ok(value) => value,
+ Err(_) => return Err(DecodeError::integer_overflow(I::WIDTH, self.codec())),
+ };
+
let number = if let Some(range) = value_constraint.constraint.range() {
match (self.options.aligned, range) {
- (_, 0) => {
- return value_constraint
- .constraint
- .minimum()
- .try_into()
- .map_err(|_| DecodeError::integer_overflow(I::WIDTH, self.codec()))
- }
+ (_, 0) => return Ok(minimum),
(true, 256) => {
self.input = self.parse_padding(self.input)?;
- self.parse_non_negative_binary_integer(range)?
+ self.parse_non_negative_binary_integer::(range)?
}
(true, 257..=K64) => {
self.input = self.parse_padding(self.input)?;
- self.parse_non_negative_binary_integer(K64)?
+ self.parse_non_negative_binary_integer::(K64)?
}
(true, OVER_K64..) => {
let range_len_in_bytes =
@@ -430,27 +430,25 @@ impl<'input> Decoder<'input> {
.ok_or_else(|| {
DecodeError::exceeds_max_length(u32::MAX.into(), self.codec())
})?;
- self.parse_non_negative_binary_integer(crate::bits::range_from_len(range))?
+ self.parse_non_negative_binary_integer::(
+ crate::bits::range_from_len(range),
+ )?
}
- (_, _) => self.parse_non_negative_binary_integer(range)?,
+ (_, _) => self.parse_non_negative_binary_integer::(range)?,
}
} else {
let bytes = &self.decode_octets()?;
-
- value_constraint
+ let number = value_constraint
.constraint
.as_start()
- .map(|_| I::try_from_unsigned_bytes(&bytes.as_raw_slice(), self.codec()))
- .unwrap_or_else(|| I::try_from_signed_bytes(&bytes.as_raw_slice(), self.codec()))?
- };
-
- let minimum: I = value_constraint
- .constraint
- .minimum()
- .try_into()
- .map_err(|_| DecodeError::integer_overflow(I::WIDTH, self.codec()))?;
+ .map(|_| I::try_from_unsigned_bytes(bytes.as_raw_slice(), self.codec()))
+ .unwrap_or_else(|| I::try_from_signed_bytes(bytes.as_raw_slice(), self.codec()))?;
- Ok(minimum.wrapping_add(number))
+ return minimum
+ .checked_add(&number)
+ .ok_or_else(|| DecodeError::integer_overflow(I::WIDTH, self.codec()));
+ };
+ Ok(minimum.wrapping_unsigned_add(number))
}
fn parse_extension_header(&mut self) -> Result {
@@ -461,13 +459,8 @@ impl<'input> Decoder<'input> {
}
// The length bitfield has a lower bound of `1..`
- let extensions_length = self.parse_normally_small_integer()? + 1;
- let (input, bitfield) =
- nom::bytes::streaming::take(usize::try_from(extensions_length).map_err(
- |e: num_bigint::TryFromBigIntError| {
- DecodeError::integer_type_conversion_failed(e.to_string(), self.codec())
- },
- )?)(self.input)
+ let extensions_length = self.parse_normally_small_integer::()? + 1;
+ let (input, bitfield) = nom::bytes::streaming::take(extensions_length)(self.input)
.map_err(|e| DecodeError::map_nom_err(e, self.codec()))?;
self.input = input;
@@ -665,11 +658,7 @@ impl<'input> crate::Decoder for Decoder<'input> {
.unwrap_or_default();
if extensible {
- let index: usize = self.parse_normally_small_integer()?.try_into().map_err(
- |e: num_bigint::TryFromBigIntError| {
- DecodeError::integer_type_conversion_failed(e.to_string(), self.codec())
- },
- )?;
+ let index: usize = self.parse_normally_small_integer()?;
E::from_extended_enumeration_index(index)
.ok_or_else(|| DecodeError::enumeration_index_not_found(index, true, self.codec()))
} else {
@@ -1006,8 +995,15 @@ impl<'input> crate::Decoder for Decoder<'input> {
});
let index = if variants.len() != 1 || is_extensible {
- usize::try_from(if is_extensible {
- self.parse_normally_small_integer()?
+ if is_extensible {
+ self.parse_normally_small_integer::()
+ .map_err(|error| {
+ DecodeError::choice_index_exceeds_platform_width(
+ usize::BITS,
+ error,
+ self.codec(),
+ )
+ })?
} else {
let variance = variants.len();
debug_assert!(variance > 0);
@@ -1016,15 +1012,15 @@ impl<'input> crate::Decoder for Decoder<'input> {
let choice_range =
constraints::Value::new(constraints::Bounded::new(0, (variance - 1) as i128))
.into();
- self.parse_integer(Constraints::new(&[choice_range]))?
- })
- .map_err(|error| {
- DecodeError::choice_index_exceeds_platform_width(
- usize::BITS,
- error.into_original().bits(),
- self.codec(),
- )
- })?
+ self.parse_integer(Constraints::new(&[choice_range]))
+ .map_err(|error| {
+ DecodeError::choice_index_exceeds_platform_width(
+ usize::BITS,
+ error,
+ self.codec(),
+ )
+ })?
+ }
} else {
0
};
diff --git a/src/per/enc.rs b/src/per/enc.rs
index bd832803..96963e66 100644
--- a/src/per/enc.rs
+++ b/src/per/enc.rs
@@ -11,7 +11,7 @@ use crate::{
strings::{
should_be_indexed, BitStr, DynConstrainedCharacterString, StaticPermittedAlphabet,
},
- BitString, Constraints, Enumerated, Tag,
+ BitString, Constraints, Enumerated, IntegerType, Tag,
},
Encode,
};
@@ -426,9 +426,9 @@ impl Encoder {
constraints::Value::new(constraints::Bounded::new(0, 63)).into()
};
- self.encode_integer_into_buffer(
+ self.encode_integer_into_buffer::(
Constraints::new(&[size_constraints]),
- &value.into(),
+ &value,
buffer,
)
}
@@ -635,50 +635,69 @@ impl Encoder {
Ok(())
}
- fn encode_integer_into_buffer(
+ fn encode_integer_into_buffer(
&mut self,
constraints: Constraints,
- value: &num_bigint::BigInt,
+ value: &I,
buffer: &mut BitString,
) -> Result<()> {
let is_extended_value = self.encode_extensible_bit(&constraints, buffer, || {
constraints.value().map_or(false, |value_range| {
- value_range.extensible.is_some() && value_range.constraint.bigint_contains(value)
+ value_range.extensible.is_some() && value_range.constraint.in_bound(value)
})
});
let value_range = if is_extended_value || constraints.value().is_none() {
- let bytes = value.to_signed_bytes_be();
- self.encode_length(buffer, bytes.len(), constraints.size(), |range| {
- Ok(BitString::from_slice(&bytes[range]))
+ let (bytes, needed) = value.to_signed_bytes_be();
+ self.encode_length(buffer, needed, constraints.size(), |range| {
+ Ok(BitString::from_slice(&bytes.as_ref()[..needed][range]))
})?;
return Ok(());
} else {
- constraints.value().unwrap()
+ // Safe to unwrap because we checked for None above
+ constraints.value().unwrap_or_default()
};
- if !value_range.constraint.bigint_contains(value) && !is_extended_value {
+ if !value_range.constraint.in_bound(value) && !is_extended_value {
return Err(Error::value_constraint_not_satisfied(
- value.clone(),
+ value.to_bigint().unwrap_or_default(),
&value_range.constraint,
self.codec(),
));
}
- let bytes = match value_range.constraint.effective_bigint_value(value.clone()) {
- either::Left(offset) => offset.to_biguint().unwrap().to_bytes_be(),
- either::Right(value) => value.to_signed_bytes_be(),
- };
-
- let effective_value: i128 =
+ let effective_range =
value_range
.constraint
- .effective_value(value.try_into().map_err(
- |e: num_bigint::TryFromBigIntError<()>| {
- Error::integer_type_conversion_failed(e.to_string(), self.codec())
- },
- )?)
- .either_into();
+ .effective_integer_value(value.to_i128().ok_or_else(|| {
+ Error::integer_type_conversion_failed(
+ "Value too large for i128 type - outside of type constraint".to_string(),
+ self.codec(),
+ )
+ })?);
+ let unsigned_ref;
+ let signed_ref;
+ let needed: usize;
+ let bytes = match &effective_range {
+ either::Left(offset) => {
+ (unsigned_ref, needed) = offset.to_unsigned_bytes_be();
+ unsigned_ref.as_ref()
+ }
+ either::Right(value) => {
+ (signed_ref, needed) = value.to_signed_bytes_be();
+ signed_ref.as_ref()
+ }
+ };
+
+ let effective_value: i128 = value_range
+ .constraint
+ .effective_value(value.to_i128().ok_or_else(|| {
+ Error::integer_type_conversion_failed(
+ "Value too large for i128 type - outside of type constraint".to_string(),
+ self.codec(),
+ )
+ })?)
+ .either_into();
const K64: i128 = SIXTY_FOUR_K as i128;
const OVER_K64: i128 = K64 + 1;
@@ -687,11 +706,11 @@ impl Encoder {
match (self.options.aligned, range) {
(true, 256) => {
self.pad_to_alignment(buffer);
- self.encode_non_negative_binary_integer(buffer, range, &bytes)
+ self.encode_non_negative_binary_integer(buffer, range, &bytes[..needed])
}
(true, 257..=K64) => {
self.pad_to_alignment(buffer);
- self.encode_non_negative_binary_integer(buffer, K64, &bytes);
+ self.encode_non_negative_binary_integer(buffer, K64, &bytes[..needed]);
}
(true, OVER_K64..) => {
let range_len_in_bytes =
@@ -704,7 +723,11 @@ impl Encoder {
&[0],
);
self.pad_to_alignment(&mut *buffer);
- self.encode_non_negative_binary_integer(&mut *buffer, 255, &bytes);
+ self.encode_non_negative_binary_integer(
+ &mut *buffer,
+ 255,
+ &bytes[..needed],
+ );
} else {
let range_value_in_bytes =
num_integer::div_ceil(crate::num::log2(effective_value + 1), 8) as i128;
@@ -717,15 +740,15 @@ impl Encoder {
self.encode_non_negative_binary_integer(
&mut *buffer,
crate::bits::range_from_len(range_value_in_bytes as u32 * 8),
- &bytes,
+ &bytes[..needed],
);
}
}
- (_, _) => self.encode_non_negative_binary_integer(buffer, range, &bytes),
+ (_, _) => self.encode_non_negative_binary_integer(buffer, range, &bytes[..needed]),
}
} else {
- self.encode_length(buffer, bytes.len(), <_>::default(), |range| {
- Ok(BitString::from_slice(&bytes[range]))
+ self.encode_length(buffer, needed, <_>::default(), |range| {
+ Ok(BitString::from_slice(&bytes[..needed][range]))
})?;
}
@@ -863,11 +886,11 @@ impl crate::Encoder for Encoder {
Ok(())
}
- fn encode_integer(
+ fn encode_integer(
&mut self,
tag: Tag,
constraints: Constraints,
- value: &num_bigint::BigInt,
+ value: &I,
) -> Result {
self.set_bit(tag, true)?;
let mut buffer = BitString::new();
@@ -1185,7 +1208,7 @@ impl crate::Encoder for Encoder {
(variance - 1) as i128,
))
.into()];
- self.encode_integer_into_buffer(
+ self.encode_integer_into_buffer::(
Constraints::from(choice_range),
&index.into(),
&mut buffer,
@@ -1398,7 +1421,7 @@ mod tests {
constraints: Constraints,
) -> Result<(), E::Error> {
encoder
- .encode_integer(tag, constraints, &self.0.into())
+ .encode_integer::(tag, constraints, &self.0.into())
.map(drop)
}
}
@@ -1421,7 +1444,7 @@ mod tests {
fn semi_constrained_integer() {
let mut encoder = Encoder::new(EncoderOptions::unaligned());
encoder
- .encode_integer(
+ .encode_integer::(
Tag::INTEGER,
Constraints::from(&[constraints::Value::from(constraints::Bounded::start_from(
-1,
@@ -1434,7 +1457,7 @@ mod tests {
assert_eq!(&[2, 0b00010000, 1], &*encoder.output.clone().into_vec());
encoder.output.clear();
encoder
- .encode_integer(
+ .encode_integer::(
Tag::INTEGER,
Constraints::from(&[
constraints::Value::from(constraints::Bounded::start_from(1)).into(),
@@ -1445,7 +1468,7 @@ mod tests {
assert_eq!(&[1, 0b01111110], &*encoder.output.clone().into_vec());
encoder.output.clear();
encoder
- .encode_integer(
+ .encode_integer::(
Tag::INTEGER,
Constraints::from(&[
constraints::Value::from(constraints::Bounded::start_from(0)).into(),
diff --git a/src/types.rs b/src/types.rs
index 9e194a04..1445686d 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -14,17 +14,18 @@ pub mod fields;
pub mod variants;
pub(crate) mod date;
+pub(crate) mod integer;
pub(crate) mod oid;
pub(crate) mod strings;
use alloc::boxed::Box;
-use num_bigint::BigUint;
pub use {
self::{
any::Any,
constraints::{Constraint, Constraints, Extensible},
instance::InstanceOf,
+ integer::{ConstrainedInteger, Integer, IntegerType},
oid::{ObjectIdentifier, Oid},
open::Open,
prefix::{Explicit, Implicit},
@@ -35,7 +36,6 @@ pub use {
},
tag::{Class, Tag, TagTree},
},
- num_bigint::BigInt as Integer,
rasn_derive::AsnType,
};
@@ -81,6 +81,7 @@ pub trait AsnType {
/// The associated tag for the type.
///
/// **Note** When implementing CHOICE types, this should be set to
+
/// [`Tag::EOC`] and instead set the [`Self::TAG_TREE`] constant to contain
/// all variants.
const TAG: Tag;
@@ -242,34 +243,6 @@ pub trait Enumerated: Sized + 'static + PartialEq + Copy + core::fmt::Debug {
}
}
-/// A integer which has encoded constraint range between `START` and `END`.
-#[derive(Debug, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
-pub struct ConstrainedInteger(pub(crate) Integer);
-
-impl AsnType for ConstrainedInteger {
- const TAG: Tag = Tag::INTEGER;
- const CONSTRAINTS: Constraints<'static> =
- Constraints::new(&[constraints::Constraint::Value(Extensible::new(
- constraints::Value::new(constraints::Bounded::const_new(START, END)),
- ))]);
-}
-
-impl core::ops::Deref for ConstrainedInteger {
- type Target = Integer;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl, const START: i128, const END: i128> From
- for ConstrainedInteger
-{
- fn from(value: T) -> Self {
- Self(value.into())
- }
-}
-
macro_rules! asn_type {
($($name:ty: $value:ident),+) => {
$(
@@ -318,182 +291,11 @@ asn_integer_type! {
u16,
u32,
u64,
- u128,
+ u128, // TODO upper constraint truncated
usize,
}
-
-pub trait IntegerType:
- Sized
- + Clone
- + core::fmt::Debug
- + TryFrom
- + TryFrom
- + TryInto
- + Into
- + num_traits::Num
- + num_traits::CheckedAdd
-{
- const WIDTH: u32;
-
- fn try_from_bytes(input: &[u8], codec: crate::Codec)
- -> Result;
-
- fn try_from_signed_bytes(
- input: &[u8],
- codec: crate::Codec,
- ) -> Result;
-
- fn try_from_unsigned_bytes(
- input: &[u8],
- codec: crate::Codec,
- ) -> Result;
-
- // `num_traits::WrappingAdd` is not implemented for `BigInt`
- #[doc(hidden)]
- fn wrapping_add(self, other: Self) -> Self;
-}
-
-macro_rules! integer_type_decode {
- ((signed $t1:ty, $t2:ty), $($ts:tt)*) => {
- impl IntegerType for $t1 {
- const WIDTH: u32 = <$t1>::BITS;
-
- fn try_from_bytes(
- input: &[u8],
- codec: crate::Codec,
- ) -> Result {
- Self::try_from_signed_bytes(input, codec)
- }
-
- fn try_from_signed_bytes(
- input: &[u8],
- codec: crate::Codec,
- ) -> Result {
- const BYTE_SIZE: usize = (<$t1>::BITS / 8) as usize;
- if input.is_empty() {
- return Err(crate::error::DecodeError::unexpected_empty_input(codec));
- }
- if input.len() > BYTE_SIZE {
- return Err(crate::error::DecodeError::integer_overflow(<$t1>::BITS, codec));
- }
-
- let mut array = [0u8; BYTE_SIZE];
- let pad = if input[0] & 0x80 == 0 { 0 } else { 0xff };
- array[..BYTE_SIZE - input.len()].fill(pad);
- array[BYTE_SIZE - input.len()..].copy_from_slice(input);
- Ok(Self::from_be_bytes(array))
- }
-
- fn try_from_unsigned_bytes(
- input: &[u8],
- codec: crate::Codec,
- ) -> Result {
- Ok(<$t2>::try_from_bytes(input, codec)? as $t1)
- }
-
- fn wrapping_add(self, other: Self) -> Self {
- self.wrapping_add(other)
- }
- }
-
- integer_type_decode!($($ts)*);
- };
- ((unsigned $t1:ty, $t2:ty), $($ts:tt)*) => {
- impl IntegerType for $t1 {
- const WIDTH: u32 = <$t1>::BITS;
-
- fn try_from_bytes(
- input: &[u8],
- codec: crate::Codec,
- ) -> Result {
- Self::try_from_unsigned_bytes(input, codec)
- }
-
- fn try_from_signed_bytes(
- input: &[u8],
- codec: crate::Codec,
- ) -> Result {
- Ok(<$t2>::try_from_bytes(input, codec)? as $t1)
- }
-
- fn try_from_unsigned_bytes(
- input: &[u8],
- codec: crate::Codec,
- ) -> Result {
- const BYTE_SIZE: usize = (<$t1>::BITS / 8) as usize;
- if input.is_empty() {
- return Err(crate::error::DecodeError::unexpected_empty_input(codec));
- }
- if input.len() > BYTE_SIZE {
- return Err(crate::error::DecodeError::integer_overflow(<$t1>::BITS, codec));
- }
-
- let mut array = [0u8; BYTE_SIZE];
- array[BYTE_SIZE - input.len()..].copy_from_slice(input);
- Ok(Self::from_be_bytes(array))
- }
-
- fn wrapping_add(self, other: Self) -> Self {
- self.wrapping_add(other)
- }
- }
-
- integer_type_decode!($($ts)*);
- };
- (,) => {};
- () => {};
-}
-
-integer_type_decode!(
- (unsigned u8, i8),
- (signed i8, u8),
- (unsigned u16, i16),
- (signed i16, u16),
- (unsigned u32, i32),
- (signed i32, u32),
- (unsigned u64, i64),
- (signed i64, u64),
- (unsigned u128, i128),
- (signed i128, u128),
- (unsigned usize, isize),
- (signed isize, usize),
-);
-
-impl IntegerType for Integer {
- const WIDTH: u32 = u32::MAX;
-
- fn try_from_bytes(
- input: &[u8],
- codec: crate::Codec,
- ) -> Result {
- if input.is_empty() {
- return Err(crate::error::DecodeError::unexpected_empty_input(codec));
- }
-
- Ok(Integer::from_signed_bytes_be(input))
- }
-
- fn try_from_signed_bytes(
- input: &[u8],
- codec: crate::Codec,
- ) -> Result {
- Self::try_from_bytes(input, codec)
- }
-
- fn try_from_unsigned_bytes(
- input: &[u8],
- codec: crate::Codec,
- ) -> Result {
- if input.is_empty() {
- return Err(crate::error::DecodeError::unexpected_empty_input(codec));
- }
-
- Ok(BigUint::from_bytes_be(input).into())
- }
-
- fn wrapping_add(self, other: Self) -> Self {
- self + other
- }
+impl AsnType for num_bigint::BigInt {
+ const TAG: Tag = Tag::INTEGER;
}
impl AsnType for str {
diff --git a/src/types/constraints.rs b/src/types/constraints.rs
index 278d0029..ecfe3cc6 100644
--- a/src/types/constraints.rs
+++ b/src/types/constraints.rs
@@ -1,4 +1,7 @@
+use super::IntegerType;
use alloc::borrow::Cow;
+use num_bigint::BigInt;
+use once_cell::race::OnceBox;
#[derive(Debug, Default, Clone)]
pub struct Constraints<'constraint>(pub Cow<'constraint, [Constraint]>);
@@ -366,7 +369,7 @@ impl Bounded {
}
}
-impl Bounded {
+impl Bounded {
pub fn as_minimum(&self) -> Option<&T> {
match self {
Self::Single(value) => Some(value),
@@ -378,7 +381,7 @@ impl Bounded {
}
pub fn minimum(&self) -> T {
- self.as_minimum().cloned().unwrap_or_default()
+ self.as_minimum().copied().unwrap_or_default()
}
}
@@ -397,38 +400,42 @@ impl + num_traits::SaturatingAdd |