asn1rs - ASN.1 Compiler for Rust
This crate generates Rust Code and optionally compatible Protobuf and SQL schema files from ASN.1 definitions. Integration with serde is supported.
The crate can be used as standalone CLI binary or used as library through its API
(for example inside your build.rs script).
Supported Features
| Feature | Parses | UPER | Protobuf | PSQL | Async PSQL |
|---|---|---|---|---|---|
| ...extensible | ✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
SEQUENCE OF |
✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes |
...SIZE(A..B) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
...SIZE(A..B,...) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
SET |
✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes |
| ...extensible | ✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
SET OF |
✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes |
...SIZE(A..B) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
...SIZE(A..B,...) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
ENUMERATED |
✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes |
| ...extensible | ✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
CHOICE |
✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes |
| ...extensible | ✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
BIT STRING |
✔️ yes | ✔️ yes | ✔️ yes¹ | ✔️ yes¹ | ✔️ yes¹ |
...SIZE(A..B) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
...SIZE(A..B,...) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
OCTET STRING |
✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes |
...SIZE(A..B) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
...SIZE(A..B,...) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
UTF8String |
✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes |
...SIZE(A..B) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
...SIZE(A..B,...) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
IA5String |
✔️ yes | ✔️ yes | ✔️ yes¹ | ✔️ yes¹ | ✔️ yes¹ |
...SIZE(A..B) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
...SIZE(A..B,...) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
NumericString |
✔️ yes | ✔️ yes | ✔️ yes¹ | ✔️ yes¹ | ✔️ yes¹ |
...SIZE(A..B) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
...SIZE(A..B,...) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
PrintableString |
✔️ yes | ✔️ yes | ✔️ yes¹ | ✔️ yes¹ | ✔️ yes¹ |
...SIZE(A..B) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
...SIZE(A..B,...) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
VisibleString |
✔️ yes | ✔️ yes | ✔️ yes¹ | ✔️ yes¹ | ✔️ yes¹ |
...SIZE(A..B) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
...SIZE(A..B,...) |
✔️ yes | ✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored |
INTEGER |
✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes |
...A..B |
✔️ yes | ✔️ yes | ✔️ yes² | ✔️ yes² | ✔️ yes² |
...A..B,... |
✔️ yes | ✔️ yes | ✔️ yes² | ✔️ yes² | ✔️ yes² |
BOOLEAN |
✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes |
OPTIONAL |
✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes |
DEFAULT ... |
✔️ yes | ||||
...INTEGER |
✔️ yes | ✔️ yes | ✔️ yes¹ | ✔️ yes¹ | ✔️ yes¹ |
...*String |
✔️ yes | ✔️ yes | ✔️ yes¹ | ✔️ yes¹ | ✔️ yes¹ |
...BOOLEAN |
✔️ yes | ✔️ yes | ✔️ yes¹ | ✔️ yes¹ | ✔️ yes¹ |
...ENUMERATED |
✔️ yes | ✔️ yes | ✔️ yes¹ | ✔️ yes¹ | ✔️ yes¹ |
NULL |
✔️ yes | ✔️ yes | ✔️ yes¹ | ✔️ yes¹ | ✔️ yes¹ |
IMPORTS..FROM..; |
✔️ yes | ||||
ObjectIdentifiers |
✔️ yes | ||||
| Value References | ✔️ yes | ||||
| ... in Range | ✔️ yes | ||||
| ... in Size | ✔️ yes | ||||
| ... in Default | ✔️ yes | ||||
WITH COMPONENTS |
✔️ yes | 🆗 ignored | 🆗 ignored | 🆗 ignored | 🆗 ignored |
- ✔️ yes: according to specification
- ✔️ yes¹: different representation
- ✔️ yes²: as close as possible to the original specification (sometimes yes, sometimes yes¹)
- 🔶 not serialized: values are not serialized or deserialized in this case, might break compatibility
- ⚠️ ignored️: constraint is ignored, this most likely breaks compatibility
- 🆗 ignored: constraint is ignored but it does not break compatibility
- ❌ ub: undefined behavior - whatever seems reasonable to prevent compiler errors and somehow transmit the value
- 🟥 error: fails to compile / translate
*The legacy UPER Reader/Writer is deprecated and will be removed in version 0.3.0
TLDR
- The new (v0.2.0) UPER Reader/Writer supports all listed features
- Protobuf, sync&async PSQL ignore most constraints
- The legacy UPER Reader/Writer does not support all features (pre v0.2.0)
Supported standards
- 📜️ ETSI TS 102 894-2 (PDF)
/ 🧰 ITS-Container (GIT):
itu-t(0) identified-organization(4) etsi(0) itsDomain(5) wg1(1) ts(102894) cdd(2) version(2) - 📜️ ETSI EN 302 637-2 (PDF)
/ 🧰 CAM-PDU-Description (GIT):
itu-t(0) identified-organization(4) etsi(0) itsDomain(5) wg1(1) en(302637) cam(2) version(2) - 📜️ ETSI EN 302 637-3 (PDF)
/ 🧰 DENM-PDU-Descriptions (GIT):
itu-t(0) identified-organization(4) etsi(0) itsDomain(5) wg1(1) en(302637) denm(1) version(2)
CLI usage
It is always helpful to check asn1rs --help in advance.
The basic usage can be seen blow:
asn1rs -t rust directory/for/rust/files some.asn1 messages.asn1
asn1rs -t proto directory/for/protobuf/files some.asn1 messages.asn1
asn1rs -t sql directory/for/sql/schema/files some.asn1 messages.asn1
Example: build.rs
The following example generates Rust, Protobuf and SQL files for all .asn1-files in the asn/ directory of a workspace.
While the generated Rust code is written to the src/ directory, the Protobuf files are written to proto/ and the SQL files are written to sql/ .
Additionally, in this example each generated Rust-Type also receives Serialize and Deserialize derive directives (#[derive(Serialize, Deserialize)]) for serde integration.
Sample build.rs file:
use Converter;
use RustCodeGenerator;
use SqlDefGenerator;
Example: Inlining ASN.1 with procedural macros
Minimal example by inlining the ASN.1 definition. For more examples see tests/.
use *;
asn_to_rust!;
Example: ASN.1-Definition converted to Rust, Protobuf and SQL
Minimal example showcasing what is being generated from an ASN.1 definition:
MyMessages DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
Header ::= SEQUENCE {
timestamp INTEGER (0..1209600000)
}
END
The generated Rust file:
use *;
// only with the feature "async-psql": Insert and query functions for async PostgreSQL
// only with the feature "psql": Insert and query functions for non-async PostgreSQL
The generated protobuf file (optional):
syntax = 'proto3';
package my.messages;
message Header {
uint32 timestamp = 1;
}
The generated SQL file (optional):
IF EXISTS Header CASCADE;
(
id SERIAL PRIMARY KEY,
timestamp INTEGER NOT NULL
);
Example: Usage of async postgres
NOTE: This requires the async-psql feature.
Using async postgres allows the message - or the batched messages - to take advantage of pipelining.
This can provide a significant speedup for deep message types (personal experience this is around 26%) compared to the synchronous/blocking postgres implementation.
use *;
use NoTls;
async
Example: Raw uPER usage
The module asn1rs::io exposes (de-)serializers and helpers for direct usage without ASN.1 definition:
use *;
use BitBuffer;
let mut buffer = default;
buffer.write_bit.unwrap;
buffer.write_utf8_string.unwrap;
send_to_another_host:
Example: Raw Protobuf usage
The module asn1rs::io::protobuf exposes (de-)serializers for protobuf usage:
use *;
let mut buffer = Vecdefault;
buffer.write_varint.unwrap;
buffer.write_string.unwrap;
send_to_another_host:
Finding deserialization error origins
For a more detailed report on deserialization errors, enable the descriptive-deserialize-errors feature.
With this feature flag more details will be memorized while deserializing your data (see ScopeDescription) - thus causing a performance penalty -
but it will list intermediate results with the error origin and the current location in the type hierarchy when displaying the error ( println!("{e}"));
TODO
Things to do at some point in time (PRs are welcome)
- generate a proper rust module hierarchy from the modules' object-identifier
- remove legacy rust+uper code generator (v0.3.0)
- support
#![no_std] - refactor / clean-up (rust) code-generators (most will be removed in v0.3.0)
- support more encoding formats of ASN.1 (help is welcome!)