ocapn-netlayer 0.1.4

OCapN transport layer interfaces and types
Documentation
use std::collections::HashMap;

use serde::{Deserialize, Serialize, Serializer};

use ocapn_syrup::Value;

#[derive(Deserialize, Debug)]
pub struct Peer {
    pub designator: String,
    pub transport: String,
    pub hints: HashMap<String, String>,
}

pub trait Uri {
    fn scheme() -> &'static str {
        "ocapn"
    }

    fn authority(&self) -> String;

    fn path(&self) -> String;

    fn query(&self) -> String;

    fn uri_string(&self) -> String {
        let mut u = Self::scheme().to_string();
        u.push_str("://");
        u.push_str(self.authority().as_str());
        let (path, query) = (self.path(), self.query());
        if !path.is_empty() {
            if let Some('/') = path.chars().nth(0) {
                u.push_str(&path);
            } else {
                u.push('/');
                u.push_str(&path);
            }
        }
        if !query.is_empty() {
            u.push('?');
            u.push_str(&query);
        }
        u
    }
}

impl Uri for Peer {
    fn authority(&self) -> String {
        format!("{}.{}", self.designator, self.transport)
    }

    fn path(&self) -> String {
        "".to_string()
    }

    fn query(&self) -> String {
        let mut qs = "".to_string();
        for (k, v) in &self.hints {
            qs.push_str(urlencoding::encode(k).into_owned().as_str());
            qs.push('=');
            qs.push_str(urlencoding::encode(v).into_owned().as_str());
        }
        qs
    }
}

impl From<&Peer> for Value {
    fn from(value: &Peer) -> Self {
        Value::Record {
            label: Box::new(Value::Symbol("ocapn-peer".to_owned())),
            fields: vec![
                Value::Symbol(value.designator.to_owned()),
                Value::Symbol(value.transport.to_owned()),
                if value.hints.is_empty() {
                    Value::Boolean(false)
                } else {
                    Value::Dictionary(
                        value
                            .hints
                            .iter()
                            .map(|(k, v)| {
                                (Value::Symbol(k.to_owned()), Value::String(v.to_owned()))
                            })
                            .collect(),
                    )
                },
            ],
        }
    }
}

impl Serialize for Peer {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_bytes(Value::from(self).to_vec().as_slice())
    }
}

pub struct SturdyRef {
    pub peer: Peer,
    pub swiss_num: String,
}

impl Uri for SturdyRef {
    fn authority(&self) -> String {
        self.peer.authority()
    }

    fn path(&self) -> String {
        format!("/s/{}", self.swiss_num)
    }

    fn query(&self) -> String {
        self.peer.query()
    }
}

impl From<&SturdyRef> for Value {
    fn from(value: &SturdyRef) -> Self {
        Value::Record {
            label: Box::new(Value::Symbol("ocapn-sturdyref".to_owned())),
            fields: vec![
                Value::from(&value.peer),
                Value::String(value.swiss_num.to_owned()),
            ],
        }
    }
}

impl Serialize for SturdyRef {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_bytes(Value::from(self).to_vec().as_slice())
    }
}