iocaine 3.0.0

The deadliest poison known to AI
Documentation
// SPDX-FileCopyrightText: 2025 Gergely Nagy
// SPDX-FileContributor: Gergely Nagy
//
// SPDX-License-Identifier: MIT

use figment::value::Value;
use kdl::{KdlDocument, KdlEntry, KdlNode};

use crate::config::{Config, Handler, Server, ServerVariant};

impl From<Config> for KdlDocument {
    fn from(config: Config) -> Self {
        let mut doc = Self::new();
        let nodes = doc.nodes_mut();

        nodes.push(config.initial_seed.to_kdl_node("initial-seed"));

        for (name, server) in &config.servers {
            nodes.push(server.to_kdl_node(name));
        }

        for (name, handler) in &config.handlers {
            nodes.push(handler.to_kdl_node(name));
        }

        doc
    }
}

trait KdlNodeWriteExt {
    fn to_kdl_node(&self, name: &str) -> KdlNode;
}

impl KdlNodeWriteExt for String {
    fn to_kdl_node(&self, name: &str) -> KdlNode {
        let mut node = KdlNode::new(name);
        node.push(KdlEntry::new(self.to_owned()));

        node
    }
}

impl KdlNodeWriteExt for Server {
    fn to_kdl_node(&self, server_name: &str) -> KdlNode {
        let (name, prefix) = match &self.variant {
            ServerVariant::Http(_) => ("http-server", "http:"),
            ServerVariant::HaproxySPOA(_) => ("haproxy-spoa-server", "haproxy-spoa:"),
            ServerVariant::Prometheus(_) => ("prometheus-server", "prometheus:"),
        };
        let mut node = KdlNode::new(name);
        node.push(KdlEntry::new(
            server_name.strip_prefix(prefix).unwrap_or(server_name),
        ));

        let children = node.ensure_children();
        let child_nodes = children.nodes_mut();

        let mut bind = KdlNode::new("bind");
        bind.push(KdlEntry::new(self.bind.to_string()));
        if let Some(socket_access) = self.unix_socket_access {
            bind.insert("unix-socket-access", socket_access.to_string());
        }
        child_nodes.push(bind);

        match &self.variant {
            ServerVariant::Http(rq) | ServerVariant::HaproxySPOA(rq) => {
                if let Some(seed) = &rq.initial_seed {
                    child_nodes.push(seed.to_kdl_node("initial-seed"));
                }

                let mut uses = KdlNode::new("use");
                uses.insert("handler-from", rq.uses.handler_from.clone());
                if let Some(metrics) = &rq.uses.metrics {
                    uses.insert(
                        "metrics",
                        metrics.strip_prefix("prometheus:").unwrap_or(metrics),
                    );
                }
                child_nodes.push(uses);
            }
            ServerVariant::Prometheus(cfg) => {
                if let Some(persist_path) = &cfg.persist_path {
                    child_nodes.push(
                        persist_path
                            .display()
                            .to_string()
                            .to_kdl_node("persist-path"),
                    );
                    child_nodes.push(cfg.persist_interval.to_kdl_node("persist-interval"));
                }
            }
        }

        node
    }
}

impl KdlNodeWriteExt for Handler {
    fn to_kdl_node(&self, handler_name: &str) -> KdlNode {
        let mut node = KdlNode::new("declare-handler");
        node.push(KdlEntry::new(handler_name.to_owned()));
        if let Some(path) = &self.path {
            node.insert("path", path.display().to_string());
        }
        node.insert("language", self.language.to_string());
        if let Some(compiler) = &self.compiler {
            node.insert("compiler", compiler.display().to_string());
        }
        if let Some(config) = &self.config {
            if !config.is_empty() {
                let children = node.ensure_children();
                let child_nodes = children.nodes_mut();

                for (name, value) in config {
                    let node = figment_value_to_kdl_node(name, value);
                    child_nodes.push(node);
                }
            }
        }

        node
    }
}

#[allow(clippy::cast_possible_wrap)]
fn figment_value_to_kdl_node(name: &str, v: &Value) -> KdlNode {
    let mut node = KdlNode::new(name.to_owned());

    match v {
        Value::String(_, s) => {
            node.push(KdlEntry::new(s.to_owned()));
        }
        Value::Char(_, c) => {
            node.push(KdlEntry::new(c.to_string()));
        }
        Value::Bool(_, b) => {
            node.push(KdlEntry::new(*b));
        }
        Value::Num(_, n) => {
            if let Some(i) = n.to_i128() {
                node.push(KdlEntry::new(i));
            } else if let Some(i) = n.to_u128() {
                node.push(KdlEntry::new(i as i128));
            }
        }
        Value::Empty(_, _) => {}
        Value::Dict(_, d) => {
            if !d.is_empty() {
                let children = node.ensure_children();
                let child_nodes = children.nodes_mut();

                for (name, value) in d {
                    let node = figment_value_to_kdl_node(name, value);
                    child_nodes.push(node);
                }
            }
        }
        Value::Array(_, a) => {
            for value in a {
                let array_node = figment_value_to_kdl_node("", value);
                for entry in array_node.entries() {
                    node.push(entry.clone());
                }
            }
        }
    }

    node
}