jay-compositor 1.15.0

The Jay compositor
use crate::client::Client;
use crate::client::ClientId;
use crate::globals::GlobalName;
use crate::ifs::wl_output::WlOutputGlobal;
use crate::tree::TreeTimeline;
use crate::tree::TreeTimeline::LiveTL;
use crate::tree::TreeTimeline::RenderTL;
use crate::tree::WorkspaceNode;
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::copyhashmap::LockableRandomState;
use crate::utils::fuse::fuse_views::FuseLinkView;
use crate::utils::fuse::fuse_views::IterDirKeyed;
use crate::utils::liveness::GetLiveness;
use crate::utils::markers::JayHash;
use crate::utils::str_fmt::StrCtx;
use crate::utils::str_fmt::StrFmt;
use crate::wire::ObjectId;
use std::rc::Rc;

pub fn format_object_link(buf: &mut String, depth: u64, client: ClientId, id: impl Into<ObjectId>) {
    format_object_link_(buf, depth, client, id.into());
}

fn format_object_link_(buf: &mut String, depth: u64, client: ClientId, id: ObjectId) {
    format_client_link(buf, depth, client);
    buf.push_str("/objects/");
    buf.push_str(itoa::Buffer::new().format(id.raw()));
}

pub fn format_output_link(buf: &mut String, depth: u64, global: &WlOutputGlobal) {
    format_path_link(buf, depth, "outputs", &global.connector.name);
}

pub fn format_workspace_link(buf: &mut String, depth: u64, ws: &WorkspaceNode) {
    format_path_link(buf, depth, "workspaces", &ws.name);
}

pub fn format_client_link(buf: &mut String, depth: u64, id: ClientId) {
    write_root_link(buf, depth);
    buf.push_str("clients/");
    buf.push_str(itoa::Buffer::new().format(id.raw()));
}

pub fn format_path_link(buf: &mut String, depth: u64, category: &str, name: &str) {
    write_root_link(buf, depth);
    buf.push_str(category);
    buf.push_str("/");
    buf.push_str(name);
}

pub fn write_root_link(buf: &mut String, depth: u64) {
    for _ in 1..depth {
        buf.push_str("../");
    }
}

pub struct DfsObjectLink;

impl FuseLinkView<Client> for DfsObjectLink {
    fn readlink(t: &Client, key: u64, depth: u64, buf: &mut String) {
        format_object_link(buf, depth, t.id, ObjectId::from_raw(key));
    }
}

pub fn write_global_link(buf: &mut String, depth: u64, name: GlobalName) {
    write_root_link(buf, depth);
    buf.push_str("globals/registry/");
    buf.push_str(itoa::Buffer::new().format(name.raw()));
}

pub struct DfsGlobalLink;

impl FuseLinkView<()> for DfsGlobalLink {
    fn readlink(_t: &(), key: u64, depth: u64, buf: &mut String) {
        write_global_link(buf, depth, GlobalName::from_raw(key as u32));
    }
}

pub trait DfsObjectLinkDirView<T>: 'static
where
    T: GetLiveness,
{
    fn client(t: &Rc<T>) -> &Rc<Client>;
    fn iter(t: &Rc<T>, key: u64, f: impl FnMut(ObjectId));
    fn contains(t: &T, key: u64, id: ObjectId) -> bool;
}

pub type DfsObjectLinkDir<V> = IterDirKeyed<dfs_object_link_dir::Dir<V>>;

mod dfs_object_link_dir {
    use crate::client::Client;
    use crate::dfs::dfs_helpers::DfsObjectLink;
    use crate::dfs::dfs_helpers::DfsObjectLinkDirView;
    use crate::utils::fuse::fuse_views::FuseLink;
    use crate::utils::fuse::fuse_views::IterDirKeyedView;
    use crate::utils::liveness::GetLiveness;
    use crate::wire::ObjectId;
    use std::marker::PhantomData;
    use std::rc::Rc;
    use std::str::FromStr;

    pub struct Dir<V>(PhantomData<fn() -> V>);

    impl<T, V> IterDirKeyedView<T> for Dir<V>
    where
        T: GetLiveness,
        V: DfsObjectLinkDirView<T>,
    {
        type Value = Client;
        type View = FuseLink<DfsObjectLink>;

        fn iter(t: Rc<T>, key: u64, mut f: impl FnMut(&str, &Rc<Self::Value>, u64)) {
            let client = V::client(&t);
            let mut buf = itoa::Buffer::new();
            V::iter(&t, key, |id| {
                f(buf.format(id.raw()), client, id.raw());
            });
        }

        fn get(t: Rc<T>, key: u64, name: &str) -> Option<(Rc<Self::Value>, u64)> {
            let id = u64::from_str(name).ok()?;
            let ok = V::contains(&t, key, ObjectId::from_raw(id));
            if !ok {
                return None;
            }
            Some((V::client(&t).clone(), id))
        }
    }
}

pub trait DfsObjectCopyHashMap {
    type Key: Copy + Eq + JayHash + Into<ObjectId> + From<ObjectId>;
    type Value;
    type RandomState: LockableRandomState;

    fn get(&self) -> &CopyHashMap<Self::Key, Self::Value, Self::RandomState>;
}

impl<K, V, R> DfsObjectCopyHashMap for CopyHashMap<K, V, R>
where
    K: Copy + Eq + JayHash + Into<ObjectId> + From<ObjectId>,
    R: LockableRandomState,
{
    type Key = K;
    type Value = V;
    type RandomState = R;

    #[inline(always)]
    fn get(&self) -> &CopyHashMap<Self::Key, Self::Value, Self::RandomState> {
        self
    }
}

pub trait DfsCopyHashMapObjectLinkDirView<T>: 'static
where
    T: GetLiveness,
{
    fn client(t: &T) -> &Rc<Client>;
    fn map(t: &T, key: u64) -> &impl DfsObjectCopyHashMap;
}

pub type DfsCopyHashMapObjectLinkDir<V> =
    DfsObjectLinkDir<dfs_copy_hash_map_object_link_dir::Dir<V>>;

mod dfs_copy_hash_map_object_link_dir {
    use crate::client::Client;
    use crate::dfs::dfs_helpers::DfsCopyHashMapObjectLinkDirView;
    use crate::dfs::dfs_helpers::DfsObjectCopyHashMap;
    use crate::dfs::dfs_helpers::DfsObjectLinkDirView;
    use crate::utils::liveness::GetLiveness;
    use crate::wire::ObjectId;
    use std::marker::PhantomData;
    use std::rc::Rc;

    pub struct Dir<V>(PhantomData<fn() -> V>);

    impl<T, V> DfsObjectLinkDirView<T> for Dir<V>
    where
        T: GetLiveness,
        V: DfsCopyHashMapObjectLinkDirView<T>,
    {
        fn client(t: &Rc<T>) -> &Rc<Client> {
            V::client(t)
        }

        fn iter(t: &Rc<T>, key: u64, mut f: impl FnMut(ObjectId)) {
            for id in V::map(t, key).get().lock().keys() {
                f((*id).into());
            }
        }

        fn contains(t: &T, key: u64, id: ObjectId) -> bool {
            V::map(t, key).get().contains(&id.into())
        }
    }
}

pub fn dfs_split_view<T>(dst: &mut String, ctx: &StrCtx<'_>, mut f: impl FnMut(TreeTimeline) -> T)
where
    T: StrFmt,
{
    ctx.struct_prefix(dst);
    ctx.struct_field(dst, "live", &f(LiveTL), true);
    ctx.struct_field(dst, "rndr", &f(RenderTL), false);
    ctx.struct_suffix(dst);
}

pub trait ClientObjectDirView<T>: 'static
where
    T: GetLiveness,
{
    type ObjectId: JayHash + Eq + Copy + Into<ObjectId> + From<ObjectId>;
    type Value;
    type RandomState: LockableRandomState;

    fn get(t: &T) -> &CopyHashMap<(ClientId, Self::ObjectId), Rc<Self::Value>, Self::RandomState>;
    fn client(v: &Self::Value) -> &Rc<Client>;
}

pub type ClientObjectDir<V> = IterDirKeyed<client_object_dir::Dir<V>>;

mod client_object_dir {
    use crate::client::Client;
    use crate::client::ClientId;
    use crate::dfs::dfs_helpers::ClientObjectDirView;
    use crate::dfs::dfs_helpers::DfsObjectLink;
    use crate::utils::fuse::fuse_views::FuseLink;
    use crate::utils::fuse::fuse_views::IterDirKeyedView;
    use crate::utils::liveness::GetLiveness;
    use crate::wire::ObjectId;
    use arrayvec::ArrayString;
    use std::marker::PhantomData;
    use std::rc::Rc;
    use std::str::FromStr;

    pub struct Dir<V>(PhantomData<fn() -> V>);

    impl<V, T> IterDirKeyedView<T> for Dir<V>
    where
        T: GetLiveness,
        V: ClientObjectDirView<T>,
    {
        type Value = Client;
        type View = FuseLink<DfsObjectLink>;

        fn iter(t: Rc<T>, _key: u64, mut f: impl FnMut(&str, &Rc<Self::Value>, u64)) {
            let mut tmp = itoa::Buffer::new();
            let mut buf = ArrayString::<41>::new();
            for ((a, b), c) in V::get(&t).lock().iter() {
                let b: ObjectId = (*b).into();
                buf.clear();
                buf.push_str(tmp.format(a.raw()));
                buf.push_str(":");
                buf.push_str(tmp.format(b.raw()));
                f(&buf, V::client(c), b.raw());
            }
        }

        fn get(t: Rc<T>, _key: u64, name: &str) -> Option<(Rc<Self::Value>, u64)> {
            let (c, o) = name.split_once(":")?;
            let client = u64::from_str(c).ok()?;
            let object = u64::from_str(o).ok()?;
            let obj = V::get(&t).get(&(
                ClientId::from_raw(client),
                ObjectId::from_raw(object).into(),
            ))?;
            Some((V::client(&obj).clone(), object))
        }
    }
}