affine_core 0.0.5

AFFiNE primitive core.
Documentation
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DocumentVariant {
  Workspace,
  Page,
  Space,
  Settings,
  Unknown,
}

impl DocumentVariant {
  pub const fn as_str(self) -> &'static str {
    match self {
      Self::Workspace => "workspace",
      Self::Page => "page",
      Self::Space => "space",
      Self::Settings => "settings",
      Self::Unknown => "unknown",
    }
  }

  fn parse(value: &str) -> Option<Self> {
    match value {
      "page" => Some(Self::Page),
      "space" => Some(Self::Space),
      "settings" => Some(Self::Settings),
      _ => None,
    }
  }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CanonicalDocumentIdentity {
  workspace_id: String,
  doc_id: String,
  variant: DocumentVariant,
}

impl CanonicalDocumentIdentity {
  pub fn workspace_id(&self) -> &str {
    &self.workspace_id
  }

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

  pub const fn variant(&self) -> DocumentVariant {
    self.variant
  }

  pub const fn is_workspace(&self) -> bool {
    matches!(self.variant, DocumentVariant::Workspace)
  }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DocumentIdentityError {
  Empty,
  WorkspaceRequired,
  InvalidFormat,
  InvalidVariant,
  DocumentRequired,
}

pub fn canonicalize_document_identity(
  raw_id: &str,
  workspace_hint: Option<&str>,
) -> Result<CanonicalDocumentIdentity, DocumentIdentityError> {
  if raw_id.is_empty() {
    return Err(DocumentIdentityError::Empty);
  }
  if workspace_hint.is_some_and(str::is_empty) {
    return Err(DocumentIdentityError::WorkspaceRequired);
  }

  let parts = raw_id.split(':').collect::<Vec<_>>();
  let (workspace, variant, doc_id) = match parts.as_slice() {
    [value] => match workspace_hint {
      Some(hint) if *value != hint => (hint, DocumentVariant::Unknown, *value),
      _ => (*value, DocumentVariant::Workspace, *value),
    },
    [variant, doc_id] => {
      let workspace = workspace_hint.ok_or(DocumentIdentityError::WorkspaceRequired)?;
      let variant = DocumentVariant::parse(variant).ok_or(DocumentIdentityError::InvalidVariant)?;
      (workspace, variant, *doc_id)
    }
    [workspace, variant, doc_id] => {
      let variant = DocumentVariant::parse(variant).ok_or(DocumentIdentityError::InvalidVariant)?;
      (workspace_hint.unwrap_or(workspace), variant, *doc_id)
    }
    [workspace, "space", "page", doc_id] => (workspace_hint.unwrap_or(workspace), DocumentVariant::Space, *doc_id),
    _ => return Err(DocumentIdentityError::InvalidFormat),
  };

  if workspace.is_empty() {
    return Err(DocumentIdentityError::WorkspaceRequired);
  }
  if !matches!(variant, DocumentVariant::Workspace) && doc_id.is_empty() {
    return Err(DocumentIdentityError::DocumentRequired);
  }

  Ok(CanonicalDocumentIdentity {
    workspace_id: workspace.to_string(),
    doc_id: doc_id.to_string(),
    variant,
  })
}

#[cfg(test)]
#[path = "../tests/access_control/document_identity/tests.rs"]
mod tests;