jay-compositor 1.15.0

The Jay compositor
use crate::client::Client;
use crate::leaks::Tracker;
use crate::object::Version;
use crate::wire::WpSecurityContextV1Id;
use crate::wire::wp_security_context_v1::*;
use jay_proc::Object;
use std::cell::Cell;
use std::cell::RefCell;
use std::rc::Rc;
use thiserror::Error;
use uapi::OwnedFd;

#[derive(Object)]
pub struct WpSecurityContextV1 {
    pub id: WpSecurityContextV1Id,
    pub client: Rc<Client>,
    pub tracker: Tracker<Self>,
    pub version: Version,
    pub listen_fd: Rc<OwnedFd>,
    pub close_fd: Rc<OwnedFd>,
    pub sandbox_engine: RefCell<Option<String>>,
    pub app_id: RefCell<Option<String>>,
    pub instance_id: RefCell<Option<String>>,
    pub committed: Cell<bool>,
}

impl WpSecurityContextV1 {
    fn check_committed(&self) -> Result<(), WpSecurityContextV1Error> {
        if self.committed.get() {
            return Err(WpSecurityContextV1Error::Committed);
        }
        Ok(())
    }
}

impl WpSecurityContextV1RequestHandler for WpSecurityContextV1 {
    type Error = WpSecurityContextV1Error;

    fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
        self.client.remove_obj(self);
        Ok(())
    }

    fn set_sandbox_engine(
        &self,
        req: SetSandboxEngine<'_>,
        _slf: &Rc<Self>,
    ) -> Result<(), Self::Error> {
        self.check_committed()?;
        let val = &mut *self.sandbox_engine.borrow_mut();
        if val.is_some() {
            return Err(WpSecurityContextV1Error::EnginSet);
        }
        *val = Some(req.name.to_string());
        Ok(())
    }

    fn set_app_id(&self, req: SetAppId<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
        self.check_committed()?;
        let val = &mut *self.app_id.borrow_mut();
        if val.is_some() {
            return Err(WpSecurityContextV1Error::AppSet);
        }
        *val = Some(req.app_id.to_string());
        Ok(())
    }

    fn set_instance_id(&self, req: SetInstanceId<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
        self.check_committed()?;
        let val = &mut *self.instance_id.borrow_mut();
        if val.is_some() {
            return Err(WpSecurityContextV1Error::InstanceSet);
        }
        *val = Some(req.instance_id.to_string());
        Ok(())
    }

    fn commit(&self, _req: Commit, _slf: &Rc<Self>) -> Result<(), Self::Error> {
        self.check_committed()?;
        self.committed.set(true);
        self.client.state.security_context_acceptors.spawn(
            &self.client.state,
            self.sandbox_engine.take(),
            self.app_id.take(),
            self.instance_id.take(),
            &self.listen_fd,
            &self.close_fd,
            self.client.bounding_caps_for_children.get(),
        );
        Ok(())
    }
}

#[derive(Debug, Error)]
pub enum WpSecurityContextV1Error {
    #[error("The sandbox engine has already been set")]
    EnginSet,
    #[error("The app id has already been set")]
    AppSet,
    #[error("The instance id has already been set")]
    InstanceSet,
    #[error("The context has already been committed")]
    Committed,
}