alef 0.115.6

Opinionated polyglot binding generator for Rust libraries
Documentation
/// Error returned by every fallible bridge call. Swift receives it as a thrown value and
/// converts it into the typed Swift error. `kind` is the variant name of the core error,
/// `status` its HTTP status and `retry_after_ms` its retry delay. A text field is empty and a number
/// is `-1` when the error does not carry it, for example an error that does not come from the
/// core crate.
pub struct AlefBridgeError {
    message: String,
    error_type: String,
    kind: String,
    status: i32,
    retry_after_ms: i64,
    payload: std::collections::BTreeMap<String, String>,
}

impl AlefBridgeError {
    pub fn message(&self) -> String {
        self.message.clone()
    }

    pub fn error_type(&self) -> String {
        self.error_type.clone()
    }

    pub fn payload(&self) -> String {
        serde_json::to_string(&self.payload).expect("error payload contains only strings")
    }

    pub fn kind(&self) -> String {
        self.kind.clone()
    }

    pub fn status(&self) -> i32 {
        self.status
    }

    pub fn retry_after_ms(&self) -> i64 {
        self.retry_after_ms
    }
}

impl From<String> for AlefBridgeError {
    fn from(message: String) -> Self {
        AlefBridgeError {
            message,
            error_type: String::new(),
            kind: String::new(),
            status: -1,
            retry_after_ms: -1,
            payload: std::collections::BTreeMap::new(),
        }
    }
}

impl From<&str> for AlefBridgeError {
    fn from(message: &str) -> Self {
        AlefBridgeError::from(message.to_string())
    }
}
{% for error in errors %}

fn alef_bridge_error_{{ error.snake }}(message: String, e: &{{ error.rust_path }}) -> AlefBridgeError {
    let {% if error.has_payload_fields %}mut {% endif %}payload = std::collections::BTreeMap::new();
    let kind = match e {
{% for variant in error.variants %}
        {{ variant.pattern }} => {
{% for field in variant.fields %}
            if let Ok(value) = serde_json::to_string({{ field.binding }}) {
                payload.insert({{ field.key }}.to_string(), value);
            }
{% endfor %}
            "{{ variant.name }}"
        },
{% endfor %}
        _ => "",
    };
    AlefBridgeError {
        message,
        error_type: "{{ error.name }}".to_string(),
        kind: kind.to_string(),
        payload,
        status: {{ error.status_expr }},
        retry_after_ms: {{ error.retry_after_expr }},
    }
}
{% endfor %}

/// Build the bridge error for `error`. The core error types give their kind, status and retry
/// delay, also when a stream or a boxed error holds them; any other error gives its message only.
pub fn alef_bridge_error<E: std::fmt::Display + 'static>(error: E) -> AlefBridgeError {
    let message = error.to_string();
    let any: &dyn std::any::Any = &error;
    let boxed_sync = any.downcast_ref::<Box<dyn std::error::Error + Send + Sync + 'static>>();
    let boxed = any.downcast_ref::<Box<dyn std::error::Error + 'static>>();
{% for error in errors %}
    if let Some(e) = any.downcast_ref::<{{ error.rust_path }}>() {
        return alef_bridge_error_{{ error.snake }}(message, e);
    }
    if let Some(e) = boxed_sync.and_then(|b| b.downcast_ref::<{{ error.rust_path }}>()) {
        return alef_bridge_error_{{ error.snake }}(message, e);
    }
    if let Some(e) = boxed.and_then(|b| b.downcast_ref::<{{ error.rust_path }}>()) {
        return alef_bridge_error_{{ error.snake }}(message, e);
    }
{% endfor %}
    let _ = (boxed_sync, boxed);
    AlefBridgeError::from(message)
}