asn1rs 0.1.13

ASN.1 to Rust, Protobuf and SQL compiler/code generator. Supports ASN.1 UPER
Documentation
# asn1rs - ASN.1 Compiler for Rust

This crate allows one to generate Rust, Protobuf and SQL code from ASN.1 definitions, providing also support for basic [serde](https://crates.io/crates/serde) integration.
The crate can be used as standalone binary using its command line interface or included invoked through its API
(for example inside the ```build.rs``` script).

The generated Rust code has serializers and deserializers for ASN.1 UPER, protobuf and PostgreSQL and can therefore communicate with other applications supporting these formats (like Java-classes generated by the Google protobuf compiler).

Currently only UPER is supported for ASN.1. 

## 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
```

## API usage

The following example generates Rust, Protobuf and SQL files for all ```.asn1```-files in the ```asn/``` directory of the project.
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 automatic [serde](https://crates.io/crates/serde) integration.

File ```build.rs```:

```rust
extern crate asn1rs;

use std::fs;

use asn1rs::converter::convert_to_proto;
use asn1rs::converter::convert_to_rust;
use asn1rs::converter::convert_to_sql;
use asn1rs::gen::rust::RustCodeGenerator;

pub fn main() {
    for entry in fs::read_dir("asn").unwrap().into_iter() {
        let entry = entry.unwrap();
        let file_name = entry.file_name().into_string().unwrap();
        if file_name.ends_with(".asn1") {
            if let Err(e) = convert_to_rust(
                entry.path().to_str().unwrap(),
                "src/",
                |generator: &mut RustCodeGenerator| {
                    generator.add_global_derive("Serialize");
                    generator.add_global_derive("Deserialize");
                },
            ) {
                panic!("Conversion to rust failed for {}: {:?}", file_name, e);
            }
            if let Err(e) = convert_to_proto(entry.path().to_str().unwrap(), "proto/") {
                panic!("Conversion to proto failed for {}: {:?}", file_name, e);
            }
            if let Err(e) = convert_to_sql(entry.path().to_str().unwrap(), "sql/") {
                panic!("Conversion to sql failed for {}: {:?}", file_name, e);
            }
        }
    }
}
```

## Example Input / Output

Input ```input.asn1```

```asn
MyMessages DEFINITIONS AUTOMATIC TAGS ::=
BEGIN

Header ::= SEQUENCE {
    timestamp    INTEGER (0..1209600000)
}

END
```

Output ```my_messages.rs```:

```rust
// use ...

#[derive(Default, Debug, Clone, PartialEq, Hash, Serialize, Deserialize)]
pub struct Header {
    pub timestamp: u32,
}

impl Header {
    pub fn timestamp_min() -> u32 {
        0
    }

    pub fn timestamp_max() -> u32 {
        1_209_600_000
    }
}

// Serialize and deserialize functions for ASN.1 UPER
impl Uper for Header { /*..*/ }

// Serialize and deserialize functions for protobuf
impl ProtobufEq for Header { /*..*/ }
impl Protobuf for Header { /*..*/ }

// Insert and query functions for PostgreSQL
impl PsqlRepresentable for Header { /*..*/ }
impl PsqlInsertable for Header { /*..*/ }
impl PsqlQueryable for Header { /*..*/ }
```

Output ```my_messages.proto```:

```proto
syntax = 'proto3';
package my.messages;

message Header {
    uint32 timestamp = 1;
}
```

Output ```my_messages.sql```:

```sql
DROP TABLE IF EXISTS Header CASCADE;

CREATE TABLE Header (
    id SERIAL PRIMARY KEY,
    timestamp INTEGER NOT NULL
);
```


## Good to know
The module ```asn1rs::io``` exposes (de-)serializers and helpers for direct usage without ASN.1 definitons:
```rust
use asn1rs::io::uper::*;
use asn1rs::io::buffer::BitBuffer;

let mut buffer = BitBuffer::default();
buffer.write_bit(true).unwrap();
buffer.write_utf8_string("My UTF8 Text").unwrap();

send_to_another_host(buffer.into::<Vec<u8>>()):
```
```rust
use asn1rs::io::protobuf::*;

let mut buffer = Vec::default();
buffer.write_varint(1337).unwrap();
buffer.wrote_string("Still UTF8 Text").unwrap();

send_to_another_host(buffer):
``` 

## What works
 - Generating Rust Code with serializtion support for
   - UPER
   - Protobuf
   - PostgreSQL
 - Generating Protobuf Definitions
 - Generating PostgreSQL Schema files
 - Support for the following ASN.1 datatypes:
   - ```SEQUENCE```, ```SEQUENCE OF```, ```CHOICE``` and ```ENUMERATED```
   - inline ```SEQUENCE OF``` and ```CHOICE``` 
   - ```OPTIONAL```
   - ```INTEGER``` with range value only (numbers or ```MIN```/```MAX```)
   - ```UTF8String```
   - ```OCTET STRING``` 
   - ```BOOLEAN```
   - using previously declared message types
   - ```IMPORTS .. FROM ..;```  
   

## What doesn't work
 - most of the (not mentioned) remaining ASN.1 data-types
 - probably most non-trivial ASN.1 declarations
 - comments
 - let me know

## TODO
Things to do at some point in time
  - support ```#![no_std]```
  - refactor / clean-up (rust) code-generators
  - async postgres


### LICENSE

MIT/Apache-2.0

### About
This crate was initially developed during a research project at IT-Designers GmbH (http://www.it-designers.de).