atomr-core 0.3.1

Actors, supervision, dispatch, mailboxes, scheduler, FSM, event stream, and coordinated shutdown — the core of the atomr actor runtime.
Documentation
//! `ActorPath` — immutable, hierarchical, string-backed path.

use std::fmt;

use serde::{Deserialize, Serialize};

use super::address::Address;

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct PathElement(String);

impl PathElement {
    pub fn new(s: impl Into<String>) -> Self {
        Self(s.into())
    }

    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for PathElement {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(&self.0)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ActorPath {
    pub address: Address,
    pub elements: Vec<PathElement>,
    pub uid: u64,
}

impl ActorPath {
    pub fn root(address: Address) -> Self {
        Self { address, elements: vec![], uid: 0 }
    }

    pub fn child(&self, name: impl Into<String>) -> Self {
        let mut e = self.elements.clone();
        e.push(PathElement::new(name));
        Self { address: self.address.clone(), elements: e, uid: 0 }
    }

    pub fn with_uid(mut self, uid: u64) -> Self {
        self.uid = uid;
        self
    }

    pub fn name(&self) -> &str {
        self.elements.last().map(|e| e.as_str()).unwrap_or("/")
    }

    pub fn parent(&self) -> Option<Self> {
        if self.elements.is_empty() {
            return None;
        }
        let mut e = self.elements.clone();
        e.pop();
        Some(Self { address: self.address.clone(), elements: e, uid: 0 })
    }

    pub fn depth(&self) -> usize {
        self.elements.len()
    }

    pub fn to_string_without_address(&self) -> String {
        let mut s = String::from("/");
        for (i, el) in self.elements.iter().enumerate() {
            if i > 0 {
                s.push('/');
            }
            s.push_str(el.as_str());
        }
        s
    }
}

impl fmt::Display for ActorPath {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}{}", self.address, self.to_string_without_address())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn builds_child_path() {
        let root = ActorPath::root(Address::local("S"));
        let user = root.child("user");
        let foo = user.child("foo");
        assert_eq!(foo.name(), "foo");
        assert_eq!(foo.depth(), 2);
        assert_eq!(foo.to_string(), "akka://S/user/foo");
    }

    #[test]
    fn parent_pops_element() {
        let root = ActorPath::root(Address::local("S")).child("user").child("a");
        assert_eq!(root.parent().unwrap().name(), "user");
    }
}