shm-rs

A Rust crate which allows to dynamically configure and read the schema based configuration files and also serialize data into JSON or binary files so later it could be deserialized into structs directly.

This crate also capable to construct a Rust structs and enumerators from the static schema files.

A statis scheme file is a file which contains a description of: - how to read user provided config file - how to store read data - how to serialize it (in which order)

A dynamic scheme file is a file which contains configurations which is required to read and serialize.

For the syntax see /docs/.

Version Log

```text V0.4.2 Added: the generator.rs now translate symbols defined in (define) to the rust code as a publicly available const, standalone fileds.

V0.4.1: Added (use) to include common structs/procedures.

V0.4: Some changes in syntax. Renamed: (allow) -> (proc-allow)

Added: (arg-enum-bind) ```

Version numbering

Until V1.0.0 this library is purely experimental and its code and syntax is subject for major changes.

Minor version number idicates changes in syntax of config files or code of the crate.

Build number is a bugfix. No changes to the code should be done.

Sequence

text ┌───────────────┐ ┌──────────────┐ │ scheme.shm │ │ config.shm │ └───────┬───────┘ └───────┬──────┘ │ │ │ │ │ │ ┌───────▼───────┐ ┌───────▼────────┐ │ │ │ │ │ File / Buffer │ │ File / Buffer │ │ │ │ │ └──────┬────────┘ └───────┬────────┘ │ │ │stream │stream │ │ ┌──────▼────────┐ ┌─────▼─────┐ │ Lexer │ │ Lexer │ └──────┬────────┘ └─────┬─────┘ │ │ │Nodes │Nodes │ │ ┌──────▼────────┐ ┌───────▼─────────┐ │ │ │ │ │ StaticScheme ├────────┬────► DynamicScheme │ │ │ │ │ │ └──────┬────────┘ │ └───────┬─────────┘ │ Structures │ │ │ Description │ │Parsed Data │ │ │ ┌──────▼────────┐ │ ┌───────▼─────────┐ │ Config │ │ │ Collected Data │ │ Structure │ │ │ Structured Data │ │ │ │ │ │ └──────┬────────┘ │ └───────┬─────────┘ │ │ │ │ │ │ ┌──────▼────────┐ │ ┌───────▼─────────┐ │ Rust Code │ │ │ │ │ Structures │ └────► Serializator │ │ Enums │ │ │ └───────────────┘ └───────┬─────────┘ │ │ ┌───────▼─────────┐ │ Serialized Data │ │ │ │ Binary or JSON │ └─────────────────┘

Example

Example of dynamic scheme file ```scheme (machine (address "01:40/5010-A3F.0") ; router's address (to access admin panel) (address "01:40/5010-A40.0") ; another adress (to access admin panel) )

;; A 100MBit interface uplink from ;; Clients from floor 2 using only this connection (interface "wan0" (phys-location "00:00:01") (address "01:40/5010-A3F") (mtu 2048u) ; 2 kiB (address-mask "01:40/5010-(A3F-A4A)") )

;; A 1Gbit interface uplink from (interface "wwan1" (phys-location "00:00:02") (address "01:40/5010-A3F") (mtu 2048u) (address-mask "01:40/5010-(A3F-A4A)") )</p> <p>;; All client machines connected to router (floor 1) (interface "lan0" (phys-location "00:01:01") (address "01:40/5010-A3F") (mtu 2048u) (address-mask "01:40/5010-A3F.(0-FFFF)") )</p> <p>;; All client machines connected to router (floor 2) (interface "lan1" (phys-location "00:01:02") (address "01:40/5010-A40") (mtu 2048u) (address-mask "01:40/5010-A40.(0-FFFF)") )</p> <p>;; Route announcement ;; Clients on lan0 would receive: ;; to: 01:40/5010-(A3F-A40) metric: 1 ;; to: 01:40/5010-any metric 1 ;; to: any metric 1 (route-table "global" (interface-alias "lan0" ; announce the following routes on interface lan0 (route-to "01:40/5010-(A3F-A40).<em>" (metric 1u) ) (route-to "01:40/5010-</em>" (via "wan0") (metric auto) ) ; routing globally to whole internet (route-to "*" (via "wwan1") (metric auto) ) )</p> <pre><code>(interface-alias "lan1" (route-to "01:40/5010-(A3F-A40).*" (metric 1u) ) (route-to "*" (via "wan0") (metric auto) ) ; do not route to global internet via wwan1 ) ;; inbound routing ;; announce to uplink that we have something on our network ;; if there are any machines that is local only then don't announce the ;; adress to uplink, so no route to host would be returned by uplink for the ;; remote host. (interface-alias "wan0" (route-to "01:40/5010-A3F.*" (via "lan0") (metric 1u) ) (route-to "01:40/5010-A40.*" (via "lan1") (metric 1u) ) ) (interface-alias "wwan1" (route-to "01:40/5010-A3F.*" (via "lan0") (metric 1u) ) ; no route to lan1 members via this interface ) </code></pre> <p>)</p> <p>```</p> <p>For the above the following static scheme is required in order to read and serialize it: ```scheme (version 1000)</p> <p>(serializator "networking" (define "auto" 0u '("metric"))</p> <pre><code>(procedure "address" (arg "a_addr" string) ) ;(struct "NetAddr" "address" ; (field "net_addr" (f/string '("a_addr"))) ;) ; -- MACHINE (procedure "machine" (proc "p_address" '("address") (proc-allow '(collection))) ) (struct "NetMachine" "machine" ;(field "nm_addrs" (f/vector (f/struct '("p_address")))) (field "nm_addrs" (f/vector (f/string '("p_address" "a_addr")))) ) ; -- COMMON (procedure "phys-location" (arg "a_phys_loc" string) ) (procedure "mtu" (arg "a_mtu" uint) ) (procedure "address-mask" (arg "a_addr_mask" string) ) ; -- INTERFACE (procedure "interface" (arg "a_if_alias" string) (proc "p_phys_loc" '("phys-location")) (proc "p_addr" '("address")) (proc "p_mtu" '("mtu") (proc-allow '(optional))) (proc "p_address_mask" '("address-mask")) ) (struct "NetInterface" "interface" (field "ni_ifalias" (f/string '("a_if_alias"))) (field "ni_ifloc" (f/string '("p_phys_loc" "a_phys_loc"))) (field "ni_addr" (f/string '("p_addr" "a_addr"))) (field "ni_ifmtu" (f/optional) (f/uint '("p_mtu" "a_mtu"))) (field "ni_ifaddr_mask" (f/string '("p_address_mask" "a_addr_mask"))) ) ; -- ROUTE-TABLE (procedure "via" (arg "a_via" string) ) (procedure "metric" (arg "a_metric" symbol uint) ) (procedure "route-to" (arg "a_route_addr" string) (proc "p_via" '("via") (proc-allow '(optional))) (proc "p_metric" '("metric")) ) (struct "NetRouteTo" "route-to" (field "rt_dest" (f/string '("a_route_addr"))) (field "rt_via" (f/optional) (f/string '("p_via" "a_via"))) (field "rt_metric" (f/uint '("p_metric" "a_metric"))) ) (procedure "interface-alias" (arg "a_route_title" string) (proc "p_route_to" '("route-to") (proc-allow '(collection))) ) (struct "NetInterfaceAlias" "interface-alias" (field "if_alias" (f/string '("a_route_title"))) (field "if_routes_to" (f/vector (f/struct '("p_route_to")))) ) (procedure "route-table" (arg "a_route_title" string) (proc "p_route_tables" '("interface-alias") (proc-allow '(collection optional))) ) (struct "NetRouteTable" "route-table" (field "rt_title" (f/string '("a_route_title"))) (field "rt_tbls" (f/optional) (f/vector (f/struct '("p_route_tables")))) ) ; -- ROOT (rootprocedure (proc "p_machine" '("machine")) (proc "p_interface" '("interface") (proc-allow '(collection))) (proc "p_route_tables" '("route-table") (proc-allow '(collection))) ) (rootstruct "Network" (field "net_machine" (f/struct '("p_machine"))) (field "net_ifs" (f/vector (f/struct '("p_interface")))) (field "net_rt_tbls" (f/vector (f/struct '("p_route_tables")))) ) </code></pre> <p>)</p> <p>```</p> <p>So the above config is serialized into: <code>json { "net_machine": { "nm_addrs": [ "01:40/5010-A3F.0", "01:40/5010-A40.0" ] }, "net_ifs": [ { "ni_ifalias": "wan0", "ni_ifloc": "00:00:01", "ni_addr": "01:40/5010-A3F", "ni_ifmtu": 2048, "ni_ifaddr_mask": "01:40/5010-(A3F-A4A)" }, { "ni_ifalias": "wwan1", "ni_ifloc": "00:00:02", "ni_addr": "01:40/5010-A3F", "ni_ifmtu": 2048, "ni_ifaddr_mask": "01:40/5010-(A3F-A4A)" }, { "ni_ifalias": "lan0", "ni_ifloc": "00:01:01", "ni_addr": "01:40/5010-A3F", "ni_ifmtu": 2048, "ni_ifaddr_mask": "01:40/5010-A3F.(0-FFFF)" }, { "ni_ifalias": "lan1", "ni_ifloc": "00:01:02", "ni_addr": "01:40/5010-A40", "ni_ifmtu": 2048, "ni_ifaddr_mask": "01:40/5010-A40.(0-FFFF)" } ], "net_rt_tbls": [ { "rt_title": "global", "rt_tbls": [ { "if_alias": "lan0", "if_routes_to": [ { "rt_dest": "01:40/5010-(A3F-A40).*", "rt_via": null, "rt_metric": 1 }, { "rt_dest": "01:40/5010-*", "rt_via": "wan0", "rt_metric": 0 }, { "rt_dest": "*", "rt_via": "wwan1", "rt_metric": 0 } ] }, { "if_alias": "lan1", "if_routes_to": [ { "rt_dest": "01:40/5010-(A3F-A40).*", "rt_via": null, "rt_metric": 1 }, { "rt_dest": "*", "rt_via": "wan0", "rt_metric": 0 } ] }, { "if_alias": "wan0", "if_routes_to": [ { "rt_dest": "01:40/5010-A3F.*", "rt_via": "lan0", "rt_metric": 1 }, { "rt_dest": "01:40/5010-A40.*", "rt_via": "lan1", "rt_metric": 1 } ] }, { "if_alias": "wwan1", "if_routes_to": [ { "rt_dest": "01:40/5010-A3F.*", "rt_via": "lan0", "rt_metric": 1 } ] } ] } ] } </code></p> <p>Raw result without formatting: <code>json {"net_machine":{"nm_addrs":["01:40/5010-A3F.0","01:40/5010-A40.0"]},"net_ifs":[{"ni_ifalias":"wan0","ni_ifloc":"00:00:01","ni_addr":"01:40/5010-A3F","ni_ifmtu":2048,"ni_ifaddr_mask":"01:40/5010-(A3F-A4A)"},{"ni_ifalias":"wwan1","ni_ifloc":"00:00:02","ni_addr":"01:40/5010-A3F","ni_ifmtu":2048,"ni_ifaddr_mask":"01:40/5010-(A3F-A4A)"},{"ni_ifalias":"lan0","ni_ifloc":"00:01:01","ni_addr":"01:40/5010-A3F","ni_ifmtu":2048,"ni_ifaddr_mask":"01:40/5010-A3F.(0-FFFF)"},{"ni_ifalias":"lan1","ni_ifloc":"00:01:02","ni_addr":"01:40/5010-A40","ni_ifmtu":2048,"ni_ifaddr_mask":"01:40/5010-A40.(0-FFFF)"}],"net_rt_tbls":[{"rt_title":"global","rt_tbls":[{"if_alias":"lan0","if_routes_to":[{"rt_dest":"01:40/5010-(A3F-A40).*","rt_via":null,"rt_metric":1},{"rt_dest":"01:40/5010-*","rt_via":"wan0","rt_metric":0},{"rt_dest":"*","rt_via":"wwan1","rt_metric":0}]},{"if_alias":"lan1","if_routes_to":[{"rt_dest":"01:40/5010-(A3F-A40).*","rt_via":null,"rt_metric":1},{"rt_dest":"*","rt_via":"wan0","rt_metric":0}]},{"if_alias":"wan0","if_routes_to":[{"rt_dest":"01:40/5010-A3F.*","rt_via":"lan0","rt_metric":1},{"rt_dest":"01:40/5010-A40.*","rt_via":"lan1","rt_metric":1}]},{"if_alias":"wwan1","if_routes_to":[{"rt_dest":"01:40/5010-A3F.*","rt_via":"lan0","rt_metric":1}]}]}]} </code></p> <p>And the following Rust code will be generated: ```rust use serde::{Serialize, Deserialize};</p> <h1>[derive(Clone, Debug, Serialize, Deserialize)]</h1> <p>pub struct NetMachine { pub nm_addrs: Vec<String> }</p> <h1>[derive(Clone, Debug, Serialize, Deserialize)]</h1> <p>pub struct NetInterface { pub ni<em>ifalias: String, pub ni</em>ifloc: String, pub ni<em>addr: String, pub ni</em>ifmtu: Option<u64>, pub ni<em>ifaddr</em>mask: String }</p> <h1>[derive(Clone, Debug, Serialize, Deserialize)]</h1> <p>pub struct NetRouteTo { pub rt<em>dest: String, pub rt</em>via: Option<String>, pub rt_metric: u64 }</p> <h1>[derive(Clone, Debug, Serialize, Deserialize)]</h1> <p>pub struct NetInterfaceAlias { pub if<em>alias: String, pub if</em>routes_to: Vec<NetRouteTo> }</p> <h1>[derive(Clone, Debug, Serialize, Deserialize)]</h1> <p>pub struct NetRouteTable { pub rt<em>title: String, pub rt</em>tbls: Option<Vec<NetInterfaceAlias>> }</p> <h1>[derive(Clone, Debug, Serialize, Deserialize)]</h1> <p>pub struct Network { pub net<em>machine: NetMachine, pub net</em>ifs: Vec<NetInterface>, pub net<em>rt</em>tbls: Vec<NetRouteTable> } ```</p> </body></html>