runar-serializer-macros

Crates.iorunar-serializer-macros
lib.rsrunar-serializer-macros
version0.1.0
created_at2025-08-14 11:58:40.330027+00
updated_at2025-08-14 11:58:40.330027+00
descriptionDerive macros for runar-serializer
homepagehttps://github.com/runar-labs/runar-rust
repositoryhttps://github.com/runar-labs/runar-rust
max_upload_size
id1794773
size20,148
Rafael Almeida (pentateu)

documentation

https://docs.rs/runar-serializer-macros

README

runar-serializer-macros

Derive and helper procedural macros for runar-serializer.

What it provides

  • #[derive(Encrypt)]: Generates a companion encrypted struct and helper methods to selectively encrypt/decrypt fields.
  • #[derive(Plain)]: Implements zero-copy conversions between your types and runar_serializer::ArcValue for efficient serialization.

Install

[dependencies]
runar-serializer-macros = "0.1"

Encrypt derive

Annotate a struct with #[derive(Encrypt)] and mark fields with zones:

  • #[runar(user)]: encrypted for the user profile key(s)
  • #[runar(system)]: encrypted for the network/system key
  • #[runar(search)]: a search index copy (encrypted) for search contexts
  • #[runar(system_only)]: only available to the system/network context

Example based on real tests:

use runar_serializer_macros::Encrypt;

#[derive(Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize, Encrypt)]
pub struct Profile {
    pub id: String,
    #[runar(system)]
    pub name: String,
    #[runar(user)]
    pub private: String,
    #[runar(search)]
    pub email: String,
    #[runar(system_only)]
    pub system_metadata: String,
}

// Generated by the macro:
// - EncryptedProfile: encrypted form
// - Profile::encrypt_with_keystore(&self, ks: &dyn EnvelopeCrypto, res: &dyn LabelResolver)
// - EncryptedProfile::decrypt_with_keystore(&self, ks: &dyn EnvelopeCrypto)

End-to-end usage (abridged)

use std::sync::Arc;
use runar_common::logging::{Component, Logger};
use runar_keys::{MobileKeyManager, NodeKeyManager};
use runar_serializer::{
    traits::{
        ConfigurableLabelResolver, EnvelopeCrypto, KeyMappingConfig, LabelKeyInfo,
        SerializationContext,
    },
    ArcValue, ValueCategory,
};

// Prepare keystores and label resolver
let logger = Arc::new(Logger::new_root(Component::System, "doc-example"));

let mut network_master = MobileKeyManager::new(logger.clone())?;
let network_id = network_master.generate_network_data_key()?;
let network_pub = network_master.get_network_public_key(&network_id)?;

let mut user_mobile = MobileKeyManager::new(logger.clone())?;
user_mobile.initialize_user_root_key()?;
let profile_pk = user_mobile.derive_user_profile_key("user")?;
user_mobile.install_network_public_key(&network_pub)?;

let mut node = NodeKeyManager::new(logger.clone())?;
let token = node.generate_csr()?;
let nk_msg = network_master.create_network_key_message(&network_id, &token.node_agreement_public_key)?;
node.install_network_key(nk_msg)?;

let resolver = Arc::new(ConfigurableLabelResolver::new(KeyMappingConfig {
    label_mappings: std::collections::HashMap::from([
        ("user".into(), LabelKeyInfo { profile_public_keys: vec![profile_pk.clone()], network_id: None }),
        ("system".into(), LabelKeyInfo { profile_public_keys: vec![profile_pk.clone()], network_id: Some(network_id.clone()) }),
        ("system_only".into(), LabelKeyInfo { profile_public_keys: vec![], network_id: Some(network_id.clone()) }),
        ("search".into(), LabelKeyInfo { profile_public_keys: vec![profile_pk.clone()], network_id: Some(network_id.clone()) }),
    ]),
}));

// Encrypt/decrypt using the generated helpers
let mobile_ks = Arc::new(user_mobile) as Arc<dyn EnvelopeCrypto>;
let node_ks = Arc::new(node) as Arc<dyn EnvelopeCrypto>;

let profile = Profile {
    id: "123".into(),
    name: "User".into(),
    private: "secret".into(),
    email: "user@example.com".into(),
    system_metadata: "sys".into(),
};

let encrypted: EncryptedProfile = profile.encrypt_with_keystore(&mobile_ks, resolver.as_ref())?;
let decrypted_for_mobile = encrypted.decrypt_with_keystore(&mobile_ks)?;
let decrypted_for_node = encrypted.decrypt_with_keystore(&node_ks)?;

// Integrate with ArcValue and optional encryption during serialization
let ctx = SerializationContext {
    keystore: mobile_ks.clone(),
    resolver: resolver.clone(),
    network_id: network_id.clone(),
    profile_public_key: Some(profile_pk.clone()),
};

let av = ArcValue::new_struct(profile);
assert_eq!(av.category(), ValueCategory::Struct);
let ser = av.serialize(Some(&ctx))?; // encrypted serialization
let de = ArcValue::deserialize(&ser, Some(node_ks.clone()))?; // decrypt with node keystore

Plain derive

#[derive(Plain)] adds efficient conversions to/from ArcValue without manual glue.

use runar_serializer_macros::Plain;

#[derive(Clone, PartialEq, Debug, serde::Serialize, serde::Deserialize, Plain)]
pub struct SimpleStruct {
    pub a: i64,
    pub b: String,
}

License

MIT. See LICENSE.

Commit count: 0

cargo fmt