// @generated by idiolect-codegen. do not edit.
// source: dev.idiolect.deliberation
//! A community-scoped question or proposal under collective consideration. Companion records `dev.idiolect.deliberationStatement` carry participant utterances, `dev.idiolect.deliberationVote` carries stances on those statements, and `dev.idiolect.deliberationOutcome` carries the observer-aggregated tally. Deliberations are intentionally process-shaped: they represent the *unsettled* moment, distinct from `dev.idiolect.belief` (settled doxastic) and `dev.idiolect.recommendation` (settled normative). A deliberation that closes can name an outcome record so consumers can read the conclusion without re-folding the votes.
#![allow(
missing_docs,
clippy::doc_markdown,
clippy::struct_excessive_bools,
clippy::derive_partial_eq_without_eq,
clippy::large_enum_variant
)]
use serde::{Deserialize, Serialize};
/// A deliberation: a topic or question owned by a community, optionally bracketed by a status and classification. Topic and description carry the human framing; classification and status are open-enum slugs resolved through community-published vocabularies, so a community can decline to take a stance on those axes simply by omitting them.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Deliberation {
/// Whether participation requires the participant be an authenticated member of `owningCommunity`. False permits drive-by statements.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub auth_required: Option<bool>,
/// Open-enum slug naming the deliberation's shape. Resolved against `classificationVocab` when present, otherwise against the canonical idiolect vocabulary.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub classification: Option<DeliberationClassification>,
/// Vocabulary the `classification` slug resolves against. Omit to use the canonical idiolect default.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub classification_vocab: Option<crate::generated::dev::idiolect::defs::VocabRef>,
/// When the deliberation moved out of an open status. Optional; absent means open or never explicitly closed.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub closed_at: Option<idiolect_records::Datetime>,
pub created_at: idiolect_records::Datetime,
/// Extended framing or context for the deliberation.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
/// AT-URI of a `dev.idiolect.deliberationOutcome` record summarising the resolved stance. Set after closure when an outcome exists; consumers can read it without re-folding the vote stream.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub outcome: Option<idiolect_records::AtUri>,
/// AT-URI of the `dev.idiolect.community` record whose membership is deliberating. Consumers resolve membership/permissions through that record.
pub owning_community: idiolect_records::AtUri,
/// Open-enum lifecycle marker. Resolved against `statusVocab` when present.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub status: Option<DeliberationStatus>,
/// Vocabulary the `status` slug resolves against.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub status_vocab: Option<crate::generated::dev::idiolect::defs::VocabRef>,
/// Human-readable topic or question.
pub topic: String,
}
impl crate::Record for Deliberation {
const NSID: &'static str = "dev.idiolect.deliberation";
}
/// DeliberationClassification. Open-enum slug; known values are kebab-cased; community-extended values pass through as `Other(String)`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum DeliberationClassification {
Question,
Proposal,
Grievance,
Retrospective,
/// Community-extended slug not present in the lexicon's
/// `knownValues`. Resolves through the sibling
/// `*Vocab` field on the containing record.
Other(String),
}
impl DeliberationClassification {
/// Wire-form slug for this value. Known variants render
/// kebab-case; the fallback variant passes through verbatim.
#[must_use]
pub fn as_str(&self) -> &str {
match self {
Self::Question => "question",
Self::Proposal => "proposal",
Self::Grievance => "grievance",
Self::Retrospective => "retrospective",
Self::Other(s) => s.as_str(),
}
}
/// Whether this slug is subsumed by `ancestor` under the
/// `subsumed_by` relation in the supplied vocab. Reflexive:
/// every slug is subsumed by itself.
#[must_use]
pub fn is_subsumed_by(
&self,
vocab: &idiolect_records::vocab::VocabGraph,
ancestor: &str,
) -> bool {
vocab.is_subsumed_by(self.as_str(), ancestor)
}
/// Whether this slug satisfies a requirement of `target`
/// under the named `relation` in the supplied vocab.
/// Generalises `is_subsumed_by` to any directed relation
/// (e.g. `stronger_than`, `provides_at_least`,
/// `equivalent_to`). Reflexive: a slug satisfies itself.
#[must_use]
pub fn satisfies(
&self,
vocab: &idiolect_records::vocab::VocabGraph,
relation: &str,
target: &str,
) -> bool {
if self.as_str() == target {
return true;
}
vocab
.walk_relation(self.as_str(), relation, false)
.iter()
.any(|n| n == target)
}
/// Translate this slug across vocabularies via
/// `equivalent_to` edges. Returns the translated slug as
/// a target enum value when a translation exists, `None`
/// when no path is found (callers fall back to passing
/// the slug through verbatim, which is wire-compatible).
#[must_use]
pub fn translate_to<T: From<String>>(
&self,
src_vocab_uri: &str,
tgt_vocab_uri: &str,
registry: &idiolect_records::vocab::VocabRegistry,
) -> Option<T> {
registry
.translate(src_vocab_uri, tgt_vocab_uri, self.as_str())
.map(T::from)
}
}
impl From<String> for DeliberationClassification {
fn from(s: String) -> Self {
match s.as_str() {
"question" => Self::Question,
"proposal" => Self::Proposal,
"grievance" => Self::Grievance,
"retrospective" => Self::Retrospective,
_ => Self::Other(s),
}
}
}
impl From<&str> for DeliberationClassification {
fn from(s: &str) -> Self {
match s {
"question" => Self::Question,
"proposal" => Self::Proposal,
"grievance" => Self::Grievance,
"retrospective" => Self::Retrospective,
_ => Self::Other(s.to_owned()),
}
}
}
impl serde::Serialize for DeliberationClassification {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl<'de> serde::Deserialize<'de> for DeliberationClassification {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(Self::from(s))
}
}
/// DeliberationStatus. Open-enum slug; known values are kebab-cased; community-extended values pass through as `Other(String)`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum DeliberationStatus {
Open,
Closed,
Tabled,
Adopted,
Rejected,
/// Community-extended slug not present in the lexicon's
/// `knownValues`. Resolves through the sibling
/// `*Vocab` field on the containing record.
Other(String),
}
impl DeliberationStatus {
/// Wire-form slug for this value. Known variants render
/// kebab-case; the fallback variant passes through verbatim.
#[must_use]
pub fn as_str(&self) -> &str {
match self {
Self::Open => "open",
Self::Closed => "closed",
Self::Tabled => "tabled",
Self::Adopted => "adopted",
Self::Rejected => "rejected",
Self::Other(s) => s.as_str(),
}
}
/// Whether this slug is subsumed by `ancestor` under the
/// `subsumed_by` relation in the supplied vocab. Reflexive:
/// every slug is subsumed by itself.
#[must_use]
pub fn is_subsumed_by(
&self,
vocab: &idiolect_records::vocab::VocabGraph,
ancestor: &str,
) -> bool {
vocab.is_subsumed_by(self.as_str(), ancestor)
}
/// Whether this slug satisfies a requirement of `target`
/// under the named `relation` in the supplied vocab.
/// Generalises `is_subsumed_by` to any directed relation
/// (e.g. `stronger_than`, `provides_at_least`,
/// `equivalent_to`). Reflexive: a slug satisfies itself.
#[must_use]
pub fn satisfies(
&self,
vocab: &idiolect_records::vocab::VocabGraph,
relation: &str,
target: &str,
) -> bool {
if self.as_str() == target {
return true;
}
vocab
.walk_relation(self.as_str(), relation, false)
.iter()
.any(|n| n == target)
}
/// Translate this slug across vocabularies via
/// `equivalent_to` edges. Returns the translated slug as
/// a target enum value when a translation exists, `None`
/// when no path is found (callers fall back to passing
/// the slug through verbatim, which is wire-compatible).
#[must_use]
pub fn translate_to<T: From<String>>(
&self,
src_vocab_uri: &str,
tgt_vocab_uri: &str,
registry: &idiolect_records::vocab::VocabRegistry,
) -> Option<T> {
registry
.translate(src_vocab_uri, tgt_vocab_uri, self.as_str())
.map(T::from)
}
}
impl From<String> for DeliberationStatus {
fn from(s: String) -> Self {
match s.as_str() {
"open" => Self::Open,
"closed" => Self::Closed,
"tabled" => Self::Tabled,
"adopted" => Self::Adopted,
"rejected" => Self::Rejected,
_ => Self::Other(s),
}
}
}
impl From<&str> for DeliberationStatus {
fn from(s: &str) -> Self {
match s {
"open" => Self::Open,
"closed" => Self::Closed,
"tabled" => Self::Tabled,
"adopted" => Self::Adopted,
"rejected" => Self::Rejected,
_ => Self::Other(s.to_owned()),
}
}
}
impl serde::Serialize for DeliberationStatus {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl<'de> serde::Deserialize<'de> for DeliberationStatus {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(Self::from(s))
}
}