tinychain 0.1.7

A next-gen database + application server
Documentation
use std::collections::HashMap;
use std::iter::FromIterator;

use log::{debug, info};

use tcgeneric::{label, Label, PathSegment, TCPath, TCPathBuf};

use crate::cluster::Cluster;
use crate::object::InstanceExt;

const RESERVED: [Label; 57] = [
    label("actor"),
    label("actors"),
    label("admin"),
    label("administration"),
    label("administrator"),
    label("auth"),
    label("authenticate"),
    label("authentication"),
    label("authorize"),
    label("authorized"),
    label("authorization"),
    label("boot"),
    label("channel"),
    label("const"),
    label("crypt"),
    label("crypto"),
    label("decrypt"),
    label("decryption"),
    label("decrypted"),
    label("dev"),
    label("encrypt"),
    label("encryption"),
    label("encrypted"),
    label("error"),
    label("https"),
    label("host"),
    label("internal"),
    label("kernel"),
    label("link"),
    label("market"),
    label("null"),
    label("official"),
    label("op"),
    label("ops"),
    label("operations"),
    label("operator"),
    label("recycle"),
    label("recycling"),
    label("secure"),
    label("security"),
    label("shortcut"),
    label("sink"),
    label("socket"),
    label("ssl"),
    label("state"),
    label("symbolic"),
    label("symlink"),
    label("sys"),
    label("system"),
    label("tls"),
    label("token"),
    label("transact"),
    label("transaction"),
    label("trash"),
    label("user"),
    label("users"),
    label("waste"),
];

#[derive(Clone)]
struct HostedNode {
    children: HashMap<PathSegment, HostedNode>,
}

pub struct Hosted {
    root: HostedNode,
    hosted: HashMap<TCPathBuf, InstanceExt<Cluster>>,
}

impl Hosted {
    fn new() -> Hosted {
        Hosted {
            root: HostedNode {
                children: HashMap::new(),
            },
            hosted: HashMap::new(),
        }
    }

    pub fn clusters(&self) -> impl Iterator<Item = &InstanceExt<Cluster>> {
        self.hosted.values()
    }

    pub fn get<'a>(
        &self,
        path: &'a [PathSegment],
    ) -> Option<(&'a [PathSegment], &InstanceExt<Cluster>)> {
        debug!("checking for hosted cluster {}", TCPath::from(path));

        let mut node = &self.root;
        let mut found_path = &path[0..0];
        for i in 0..path.len() {
            if let Some(child) = node.children.get(&path[i]) {
                found_path = &path[..i + 1];
                node = child;
            } else if let Some(cluster) = self.hosted.get(found_path) {
                return Some((&path[found_path.len()..], cluster));
            } else {
                return None;
            }
        }

        if let Some(cluster) = self.hosted.get(found_path) {
            Some((&path[found_path.len()..], cluster))
        } else {
            None
        }
    }

    fn push(&mut self, cluster: InstanceExt<Cluster>) {
        if cluster.path().is_empty() {
            panic!("Cannot host a cluster at /");
        } else {
            for id in &RESERVED {
                if &cluster.path()[0] == id {
                    panic!("Cannot host a cluster at reserved path /{}", id);
                }
            }
        }

        let mut node = &mut self.root;
        for segment in cluster.path().iter().cloned() {
            node = node.children.entry(segment).or_insert(HostedNode {
                children: HashMap::new(),
            });
        }

        info!("Hosted {}", cluster);
        self.hosted.insert(cluster.path().to_vec().into(), cluster);
    }
}

impl FromIterator<InstanceExt<Cluster>> for Hosted {
    fn from_iter<I: IntoIterator<Item = InstanceExt<Cluster>>>(iter: I) -> Self {
        let mut hosted = Hosted::new();

        for cluster in iter.into_iter() {
            hosted.push(cluster);
        }

        hosted
    }
}