use crate::prelude::*;
use crate::schema::namespaces::schema_org;
use crate::schema::TechnologyReadinessLevel;
use crate::util::{LinkedData, ToMarkdown};
use bon::Builder;
use derive_more::Display;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
pub mod data;
pub use data::{Availability, Data, DataDescription, DataDescriptionContext, DataReadinessLevel, GeospatialDataProcessingLevel, Modality, Quality};
#[derive(Clone, Debug, Display, Deserialize, Serialize, JsonSchema)]
#[repr(u8)]
#[serde(deny_unknown_fields)]
pub enum Autonomy {
#[display("Manual")]
Manual = 0,
#[display("Machine-assisted")]
MachineAssisted = 1,
#[display("Human-as-primary")]
HumanPrimary = 2,
#[display("Machine-as-primary")]
MachinePrimary = 3,
#[display("Human-supervised")]
HumanAware = 4,
#[display("Machine-only")]
MachineOnly = 5,
}
#[derive(Clone, Debug, Default, Deserialize_repr, Display, Serialize_repr, PartialEq, PartialOrd, JsonSchema)]
#[repr(u8)]
#[serde(deny_unknown_fields)]
pub enum Maturity {
#[default]
#[display("Unvalidated")]
Unvalidated = 0,
#[display("Discovery")]
Discovery = 1,
#[display("Concept")]
Concept = 2,
#[display("Development")]
Development = 3,
#[display("Prototype")]
Prototype = 4,
#[display("Proven")]
Proven = 5,
}
#[derive(Clone, Debug, Default, Display, Deserialize, Serialize, JsonSchema)]
#[repr(u8)]
#[serde(deny_unknown_fields)]
pub enum Motivity {
#[default]
#[display("Inert")]
Inert = 0,
#[display("Computational")]
Computational = 1,
#[display("Perceptive")]
Perceptive = 2,
#[display("Projective")]
Projective = 3,
#[display("Reactive")]
Reactive = 4,
#[display("Adaptive")]
Adaptive = 5,
}
#[derive(Clone, Debug, Default, Display, Deserialize, Serialize, JsonSchema)]
#[repr(u8)]
#[serde(deny_unknown_fields)]
pub enum SoftwarePortability {
#[default]
Limited = 0,
Source = 1,
Containerized = 2,
Installable = 3,
AutomatedInstaller = 4,
WebAssembly = 5,
}
#[derive(Clone, Debug, Default, Display, Deserialize_repr, Serialize_repr, PartialEq, PartialOrd, JsonSchema)]
#[repr(u8)]
#[serde(deny_unknown_fields)]
pub enum VisidataMachineAssistanceLevel {
#[default]
#[display("Level 0: No Machine Assistance")]
NoMachineAssistance = 0,
#[display("Level 1: Ideation Only")]
IdeationOnly = 1,
#[display("Level 2: Trivial Machine Assistance")]
Trivial = 2,
#[display("Level 3: Non-Trivial Machine Assistance")]
NonTrivial = 3,
#[display("Level 4: Significant Machine Assistance")]
Significant = 4,
#[display("Level 5: Machine Generated, Human Verified")]
MachineGeneratedHumanVerified = 5,
#[display("Level 6: Machine Generated, Human Supervised")]
MachineGeneratedHumanSupervised = 6,
#[display("Level 7: Human Specified, Machine Implemented")]
HumanSpecifiedMachineImplemented = 7,
#[display("Level 8: Autonomous with Human Approval")]
AutonomousWithHumanApproval = 8,
#[display("Level 9: Autonomous without Oversight")]
AutonomousWithoutOversight = 9,
#[display("Level 10: Unsolicited Machine Action")]
UnsolicitedMachineAction = 10,
}
#[derive(Builder, Clone, Debug, Deserialize, Serialize, JsonSchema)]
#[builder(start_fn = init)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct AspectFramework {
#[serde(rename = "@context")]
pub context: Option<AspectFrameworkContext>,
#[serde(rename = "@type")]
pub aspect_type: Option<String>,
pub data: Option<Vec<Data>>,
pub portability: Option<SoftwarePortability>,
pub motivity: Option<Motivity>,
pub autonomy: Option<Autonomy>,
pub maturity: Option<TechnologyReadinessLevel>,
}
#[derive(Builder, Clone, Debug, Deserialize, Serialize, JsonSchema)]
#[builder(start_fn = init, on(String, into))]
pub struct AspectFrameworkContext {
pub(crate) data: String,
pub(crate) portability: String,
pub(crate) motivity: String,
pub(crate) autonomy: String,
pub(crate) maturity: String,
}
impl Default for AspectFramework {
fn default() -> Self {
AspectFramework::init().build()
}
}
impl Default for AspectFrameworkContext {
fn default() -> Self {
AspectFrameworkContext::init()
.data(schema_org("DefinedTerm"))
.portability(schema_org("DefinedTerm"))
.motivity(schema_org("DefinedTerm"))
.autonomy(schema_org("DefinedTerm"))
.maturity(schema_org("DefinedTerm"))
.build()
}
}
impl ToMarkdown for AspectFramework {
fn to_markdown(&self) -> String {
let summary = [
self.portability.as_ref().map(|value| format!("- Portability: {value}")),
self.maturity.as_ref().map(|value| format!("- Maturity: {value}")),
self.autonomy.as_ref().map(|value| format!("- Autonomy: {value}")),
self.motivity.as_ref().map(|value| format!("- Motivity: {value}")),
]
.into_iter()
.flatten()
.collect::<Vec<_>>();
let data = self
.data
.as_ref()
.map(|values| values.iter().map(ToMarkdown::to_markdown).collect::<Vec<_>>())
.filter(|values| !values.is_empty())
.map(|values| format!("\n\n### Data\n{}", values.join("\n")))
.unwrap_or_default();
if summary.is_empty() && data.is_empty() {
"## ASPECT\n[]".to_string()
} else {
format!("## ASPECT\n{}{}", summary.join("\n"), data)
}
}
}
impl From<VisidataMachineAssistanceLevel> for Autonomy {
fn from(level: VisidataMachineAssistanceLevel) -> Self {
match level {
| VisidataMachineAssistanceLevel::NoMachineAssistance | VisidataMachineAssistanceLevel::IdeationOnly => Autonomy::Manual,
| VisidataMachineAssistanceLevel::Trivial | VisidataMachineAssistanceLevel::NonTrivial => Autonomy::MachineAssisted,
| VisidataMachineAssistanceLevel::Significant => Autonomy::HumanPrimary,
| VisidataMachineAssistanceLevel::MachineGeneratedHumanVerified | VisidataMachineAssistanceLevel::MachineGeneratedHumanSupervised => {
Autonomy::MachinePrimary
}
| VisidataMachineAssistanceLevel::HumanSpecifiedMachineImplemented | VisidataMachineAssistanceLevel::AutonomousWithHumanApproval => {
Autonomy::HumanAware
}
| VisidataMachineAssistanceLevel::AutonomousWithoutOversight | VisidataMachineAssistanceLevel::UnsolicitedMachineAction => {
Autonomy::MachineOnly
}
}
}
}
impl LinkedData for AspectFramework {
fn with_context(&self) -> Self {
Self {
context: Some(AspectFrameworkContext::default()),
aspect_type: None,
..self.clone()
}
}
}
impl From<TechnologyReadinessLevel> for Maturity {
fn from(value: TechnologyReadinessLevel) -> Self {
match value {
| TechnologyReadinessLevel::Principles | TechnologyReadinessLevel::Research => Self::Discovery,
| TechnologyReadinessLevel::Concept | TechnologyReadinessLevel::Feasible => Self::Concept,
| TechnologyReadinessLevel::Developing | TechnologyReadinessLevel::Developed => Self::Development,
| TechnologyReadinessLevel::Prototype | TechnologyReadinessLevel::Operational | TechnologyReadinessLevel::MissionReady => Self::Prototype,
| TechnologyReadinessLevel::MissionCapable => Self::Proven,
}
}
}