Rust types for the OASIS Common Alerting Protocol (CAP)

Overview

oasiscap

Types for the OASIS Common Alerting Protocol.

Example

43b080713727 [email protected] 2003-04-02T14:39:01-05:00 Actual Alert Public "#?; match &alert { oasiscap::Alert::V1dot0(alert) => println!("CAP v1.0: {:?}", alert), oasiscap::Alert::V1dot1(alert) => println!("CAP v1.1: {:?}", alert), oasiscap::Alert::V1dot2(alert) => println!("CAP v1.2: {:?}", alert), } // Upgrade to the latest CAP version let alert: oasiscap::v1dot2::Alert = alert.into_latest(); // Convert back to XML again let alert_xml = alert.to_string();">
let alert: oasiscap::Alert = r#"


   
  
   
    43b080713727
   
  
   
    [email protected]
   
  
   
    2003-04-02T14:39:01-05:00
   
  
   
    Actual
   
  
   
    Alert
   
  
   
    Public
   
  
   
    
  

"#?;

match &alert {
    oasiscap::Alert::V1dot0(alert) => println!("CAP v1.0: {:?}", alert),
    oasiscap::Alert::V1dot1(alert) => println!("CAP v1.1: {:?}", alert),
    oasiscap::Alert::V1dot2(alert) => println!("CAP v1.2: {:?}", alert),
}

// Upgrade to the latest CAP version
let alert: oasiscap::v1dot2::Alert = alert.into_latest();

// Convert back to XML again
let alert_xml = alert.to_string();

Conformance

The CAP specifications are split between human- and machine-readable components. CAP v1.2 § 4.2 explains:

An XML 1.0 document is a conforming CAP V1.2 Message if and only if:

a) it is valid according to the schema and

b) the content of its elements and the values of its attributes meet all the additional mandatory requirements specified in Section 3.

Consider the element. The machine-readable XML schema says that a polygon is just a string:

">
<element name = "polygon" type = "xs:string" minOccurs = "0" maxOccurs = "unbounded"/>

The human-readable document says that a polygon is specifically a string describing a closed polyline in a particular geospatial reference frame, and imposes the following requirements in section 3:

(1) Code Values: The geographic polygon is represented by a whitespace-delimited list of WGS 84 coordinate pairs. (See WGS 84 Note at end of this section)

(2) A minimum of 4 coordinate pairs MUST be present and the first and last pairs of coordinates MUST be the same.

This crate implements those rules from section 3:

().is_ok()); // 4 points where the last point differs does not make a Polygon: assert!("1,1 2,2 3,3 4,4".parse:: ().is_err()); // 3 points does not make a Polygon: assert!("1,1 2,2 1,1".parse:: ().is_err()); // invalid WGS-84 coordinates do not make a Polygon: assert!("100,100 200,200 300,300 100,100".parse:: ().is_err());">
use oasiscap::geo::Polygon;

// 4 points, where the last point is the first point, makes a Polygon:
assert!("1,1 2,2 3,3 1,1".parse::
      ().
      is_ok());


      // 4 points where the last point differs does not make a Polygon:

      assert!(
      "1,1 2,2 3,3 4,4".
      parse
      ::
      
       ().
       is_err());


       // 3 points does not make a Polygon:

       assert!(
       "1,1 2,2 1,1".
       parse
       ::
       
        ().
        is_err());


        // invalid WGS-84 coordinates do not make a Polygon:

        assert!(
        "100,100 200,200 300,300 100,100".
        parse
        ::
        
         ().
         is_err());
        
       
      
     

All of those strings are permitted by the XML schema, but only the first one makes sense as a polygon. This crate therefore accepts the first string and rejects the others.

Having said that, some real-world CAP alerts violate the requirements in section 3 but do still make sense:

<polygon>polygon>

Polygons are optional, so the element can and should have been omitted in its entirety. On the other hand, an empty string is valid according to the XML schema, and its intent is unambiguous even if it is technically non-conforming. This crate therefore accepts an empty polygon element as a synonym for omitting the polygon, rather than returning an error.

This crate intends to always parse conforming CAP messages and to always generate conforming CAP messages. At the same time, this crate intends to be pedantic to preserve meaning, not to be pendantic for pedantry's sake. It therefore does not reject all non-conforming CAP messages, particularly for common implementation mistakes which have reasonable and unambiguous interpretations.

Performance

oasiscap prioritizes being correct over being fast, but it is still reasonably fast. On an industry standard developer's laptop using unspecified versions of this library, Rust, and the underlying operating system, parsing a typical oasiscap::Alert from XML takes approximately 55µs, for a throughput of roughly 18,000 alerts per second per core. Generating XML from a typical oasiscap::Alert takes approximately 27µs, for a throughput of roughly 38,000 alerts per second per core.

Clone the repository and run cargo bench to see how it performs in your environment.

Protocol Buffers

Google Public Alerts defines a CAP Protocol Buffers representation, under the Java package name com.google.publicalerts.cap. This crate optionally provides oasiscap::protobuf when built with the prost feature. oasiscap::protobuf data types exactly correspond to these Protocol Buffers message types.

The Protocol Buffers representations are more permissive than the usual parsed oasiscap types: timestamps can lack time zones, polygons don't have to be closed, required fields can be missing, etc. This crate therefore also provides conversions:

// Decoding from protobuf bytes can fail:
let protobuf_alert: oasiscap::protobuf::Alert = prost::Message::decode(
    protobuf_encoded_bytes.as_slice()
)?;

// Converting to an `oasiscap::Alert` can fail:
let alert: oasiscap::Alert = protobuf_alert.try_into()?;

// Converting back to an `oasiscap::protobuf::Alert` cannot fail:
let alert: oasiscap::protobuf::Alert = alert.into();

// Nor can encoding protobuf bytes:
let protobuf_encoded_bytes = prost::Message::encode_to_vec(&alert);

Protocol Buffers offer substantially better performance than XML:

  • &[u8] to oasiscap::protobuf::Alert: 2µs
  • oasiscap::protobuf::Alert to oasiscap::Alert: 2µs
  • oasiscap::Alert to oasiscap::protobuf::Alert: 1µs
  • oasiscap::protobuf::Alert to Vec : 0.3µs
You might also like...
A repository full of manually generated hand curated JSON files, which contain the API Types that the Discord API returns.

Discord API Types A repository full of manually generated hand curated JSON files, which contain the API Types that the Discord API returns. Also did

Option and Either types with variants known at compile time.

Const Either Some types to allow deciding at compile time if an option contains a value or which variant from the either type is active. This might be

Application that simulates a large grid of Pokémon types fighting each other.
Application that simulates a large grid of Pokémon types fighting each other.

poke-fighting-rust Rust project that simulates a grid of Pokémon fighting with each other. Each Pokémon type is a pixel on the grid and is represented

This contract implements simple vote for the best coffe in indonesia using near protocol.

vote-coffe-near Description This contract implements simple vote for the best coffe in indonesia using near protocol. Contract in contract/src/lib.rs

📦  Crate Protocol allows anyone to create, manage, and trade a tokenized basket of assets, which we refer to as a Crate.
📦 Crate Protocol allows anyone to create, manage, and trade a tokenized basket of assets, which we refer to as a Crate.

📦 Crate Protocol Crate Protocol allows anyone to create, manage, and trade a tokenized basket of assets, which we refer to as a Crate. A Crate is alw

Asset-Pool is a decentralized lending protocol and enables users to lend through their social networks

Run If you need to, set up your Substrate development environment . Then, build and run a development chain: $ cargo run -- --dev --tmp Once the node

Default implementation of the Wayland protocol for use with wl

Wayland An implementation of core Wayland interfaces and convenience functions for accelerating the development of Wayland clients and servers using t

First Git on Rust is reimplementation with rust in order to learn about rust, c and git.

First Git on Rust First Git on Rust is reimplementation with rust in order to learn about rust, c and git. Reference project This project refer to the

A stupid macro that compiles and executes Rust and spits the output directly into your Rust code

inline-rust This is a stupid macro inspired by inline-python that compiles and executes Rust and spits the output directly into your Rust code. There

Common processing blocks used with your Runes.

Common Processing Blocks (API Docs) Processing blocks built by Hammer of the Gods that you can use with your Runes. License This project is licensed u

Hammer of the Gods 9 Jul 21, 2022
Slack bot for self-servicing automation of common or predictable tasks.

receptionist-bot-rs Slack bot for self-servicing automation of common or predictable tasks. Receptionist bot aims to provide a no-code frontend for te

Twilio Labs 16 Dec 23, 2022
Traits for inspecting memory usage of Rust types

memuse This crate contains traits for measuring the dynamic memory usage of Rust types. About Memory-tracking is a common activity in large applicatio

null 13 Dec 23, 2022
Annoyed that Rust has many string types? Well it doesn't have to

generic-str The one true string type in Rust! This project intends to be a proof-of-concept for an idea I had a few months back. There is lots of unsa

Conrad Ludgate 40 Apr 9, 2022
Use explicit container types with Scrypto! Leverage the Rust compiler's type checking to increase security and productivity when developing Radix blueprints.

Scrypto Static Types Use explicit container types with Scrypto! Leverage the Rust compiler's type checking to increase security and productivity when

null 7 Aug 5, 2022
A rust program to try and detect some types of Hardware Keyloggers.

Hardware Keylogger Detection Warning: Certain Types of Hardware keyloggers can not be detected by this program, Passive Hardware Keyloggers are imposs

null 4 Dec 5, 2022
The most primitive and the fastest implementation of a fixed-size last-in-first-out stack on stack in Rust, for Copy-implementing types

This is the simplest and the fastest (faster than Vec!) implementation of a last-in-first-out stack data structure, on stack, when stack elements are

Yegor Bugayenko 10 Jun 18, 2023
A list of known SS58 account types as an enum.

A list of known SS58 account types as an enum.

Parity Technologies 39 Dec 14, 2022
🪣 Types for a `Vec`'s raw parts

raw-parts A wrapper around the decomposed parts of a Vec<T>. This struct contains the Vec's internal pointer, length, and allocated capacity. RawParts

Artichoke Ruby 3 Sep 1, 2022
An unsafe botched job that doesn't rely on types being 'static lifetime.

An unsafe botched job that doesn't rely on types being 'static lifetime. Will panic if provided a 0 field struct. I will fix this when I figure out how.

twhite 0 Feb 4, 2022