use crate::*; use std::collections::BTreeMap; fn add(p: &mut Project, kind: Kind, layer: Layer, name: &str, parent: Option) -> Id { p.add_element(kind, layer, name, parent).unwrap() } fn occurrence( p: &mut Project, owner: Id, layer: Layer, name: &str, exchange: Id, sender: Option, receiver: Option, ) -> Id { let id = add(p, Kind::Occurrence, layer, name, Some(owner)); *p.elements.get_mut(&id).unwrap().shared_mut().unwrap() = SharedBody::Occurrence { body: OccurrenceBody::Exchange { operation: None, exchange: Some(exchange), sender, receiver, message_kind: MessageKind::Asynchronous, reply_to: None, values: vec![], }, precondition: String::new(), postcondition: String::new(), }; p.elements .get_mut(&owner) .unwrap() .steps_mut() .unwrap() .push(id); id } fn port(p: &mut Project, owner: Id, name: &str, direction: PortDirection, interface: Id) -> Id { let items = crate::data::interface_items(p, interface); let contract = if p.elements[&owner].kind() == Kind::Function { if direction == PortDirection::Out { PortContract::FunctionOutput { outgoing_items: items, } } else { PortContract::FunctionInput { incoming_items: items, } } } else { PortContract::Component { kind: ComponentPortKind::Flow, orientation: match direction { PortDirection::In => ComponentPortOrientation::In, PortDirection::Out => ComponentPortOrientation::Out, PortDirection::InOut => ComponentPortOrientation::InOut, }, } }; let id = Id::new_v4(); let element = crate::ports::make_port(p, id, owner, name, contract).unwrap(); p.elements.insert(id, element); id } fn diagram( p: &mut Project, layer: Layer, projection: ProjectionKind, name: &str, elements: &[Id], ) -> Id { let id = Id::new_v4(); let alias = p.fresh_alias(name, "diagram", id); p.diagrams.insert( id, Diagram { id, alias, name: name.into(), description: "A focused projection of the shared engineering model.".into(), layer, projection, view_options: Default::default(), nodes: BTreeMap::new(), routes: vec![], }, ); for (index, e) in elements.iter().enumerate() { p.place( id, *e, Position { x: 60. + (index % 4) as f32 * 280., y: 70. + (index / 4) as f32 * 170., }, ); } id } fn trace(p: &mut Project, oa: Id, sa: Id, kind: TraceKind) { let id = Id::new_v4(); let name = format!("{} ↔ {}", p.named(oa), p.named(sa)); let alias = p.fresh_alias(&format!("trace_{}", p.named(oa)), "trace", id); p.traces.insert( id, Trace { id, alias, name, description: "Reviewed OA/SA correspondence in the coastal rescue example.".into(), oa, sa, kind, baseline: Some(TraceBaseline { oa: p.properties(oa).unwrap(), sa: p.properties(sa).unwrap(), semantic: None, }), }, ); } pub fn coastal_rescue() -> Project { let mut p = Project::empty(); p.name = "Coastal rescue — operational need to system behavior".into(); p.description="A worked OA/SA example. Compare allocation and functional decomposition views; inspect traces, repeated scenario messages, interface contracts, degraded modes, and external engineering artifacts.".into(); let coordination = add(&mut p, Kind::Entity, Layer::Oa, "Rescue coordination", None); let vessel = add(&mut p, Kind::Actor, Layer::Oa, "Vessel in distress", None); let role = add(&mut p, Kind::Role, Layer::Oa, "Incident coordinator", None); let oa_parent = add( &mut p, Kind::Activity, Layer::Oa, "Respond to distress", None, ); let report = add( &mut p, Kind::Activity, Layer::Oa, "Report distress", Some(oa_parent), ); let assess = add( &mut p, Kind::Activity, Layer::Oa, "Assess incident", Some(oa_parent), ); let oa_cap = add( &mut p, Kind::Capability, Layer::Oa, "Protect life at sea", None, ); let process = add( &mut p, Kind::Process, Layer::Oa, "Distress to response", None, ); let oa_item = add( &mut p, Kind::ExchangeItem, Layer::Oa, "Distress report", None, ); if let Some(SharedBody::ExchangeItem { mechanism, .. }) = p.elements.get_mut(&oa_item).unwrap().shared_mut() { *mechanism = ExchangeMechanism::Event; } p.relate(RelationKind::Allocation, "Reports distress", vessel, report); p.relate( RelationKind::Allocation, "Assesses incident", coordination, assess, ); p.relate( RelationKind::RoleRealization, "Fulfils coordinator role", coordination, role, ); p.relate( RelationKind::RoleAssignment, "Coordinates assessment", role, assess, ); let interaction = p.relate(RelationKind::Interaction, "Distress signal", report, assess); if let RelationBody::Interaction { items, .. } = &mut p.relations.get_mut(&interaction).unwrap().body { items.push(oa_item); } p.relate( RelationKind::CapabilityInvolvement, "Operational contribution", assess, oa_cap, ); p.relate( RelationKind::ChainInvolvement, "Operational realization", process, oa_cap, ); let oa_occurrence = occurrence( &mut p, process, Layer::Oa, "Distress received", interaction, None, None, ); let system = add( &mut p, Kind::System, Layer::Sa, "Rescue coordination system", None, ); let actor = add( &mut p, Kind::SystemActor, Layer::Sa, "Vessel communication service", None, ); let sa_parent = add( &mut p, Kind::Function, Layer::Sa, "Manage distress response", None, ); let transmit = add( &mut p, Kind::Function, Layer::Sa, "Transmit distress report", Some(sa_parent), ); let coordinate = add( &mut p, Kind::Function, Layer::Sa, "Classify incident and alert operator", Some(sa_parent), ); let sa_cap = add( &mut p, Kind::SystemCapability, Layer::Sa, "Coordinate rescue response", None, ); let chain = add( &mut p, Kind::FunctionalChain, Layer::Sa, "Digital distress handling", None, ); let mission = add( &mut p, Kind::Mission, Layer::Sa, "Support timely rescue decisions", None, ); p.relate( RelationKind::Allocation, "Vessel transmission", actor, transmit, ); p.relate( RelationKind::Allocation, "System assessment", system, coordinate, ); p.relate( RelationKind::CapabilityInvolvement, "System capability support", coordinate, sa_cap, ); p.relate( RelationKind::ChainInvolvement, "Functional chain support", chain, sa_cap, ); p.relate( RelationKind::MissionCapability, "Mission capability", mission, sa_cap, ); let information = add( &mut p, Kind::ExchangeItem, Layer::Sa, "Digital distress report", None, ); if let Some(SharedBody::ExchangeItem { mechanism, .. }) = p.elements.get_mut(&information).unwrap().shared_mut() { *mechanism = ExchangeMechanism::Event; } let material = add( &mut p, Kind::ExchangeItem, Layer::Sa, "Rescue supply package", None, ); *p.elements.get_mut(&material).unwrap().shared_mut().unwrap() = SharedBody::ExchangeItem { kind: ExchangeItemKind::Material, mechanism: ExchangeMechanism::Flow, supertype: None, }; let energy = add( &mut p, Kind::ExchangeItem, Layer::Sa, "Backup electrical energy", None, ); *p.elements.get_mut(&energy).unwrap().shared_mut().unwrap() = SharedBody::ExchangeItem { kind: ExchangeItemKind::Energy, mechanism: ExchangeMechanism::Flow, supertype: None, }; let field = add( &mut p, Kind::DataField, Layer::Sa, "Reported latitude", Some(information), ); *p.elements.get_mut(&field).unwrap().shared_mut().unwrap() = SharedBody::DataField { type_ref: TypeRef::Real, minimum: 1, maximum: Some(1), unit: "degrees north".into(), direction: ParameterDirection::Unspecified, storage: FieldStorage::Value, default: None, }; let interface = add( &mut p, Kind::Interface, Layer::Sa, "Distress reporting interface", None, ); p.relate( RelationKind::InterfaceItemAllocation, "Distress payload", interface, information, ); let vessel_port = port( &mut p, actor, "Vessel reporting output", PortDirection::Out, interface, ); let system_port = port( &mut p, system, "System reporting input", PortDirection::In, interface, ); let function_out = port( &mut p, transmit, "Report function output", PortDirection::Out, interface, ); let function_in = port( &mut p, coordinate, "Assessment function input", PortDirection::In, interface, ); let exchange = p.relate( RelationKind::FunctionalExchange, "Validated distress report", transmit, coordinate, ); p.relations.get_mut(&exchange).unwrap().body = RelationBody::FunctionalExchange { source: transmit, target: coordinate, source_port: function_out, target_port: function_in, items: vec![information], }; let boundary = p.relate( RelationKind::BoundaryExchange, "Distress reporting connection", vessel_port, system_port, ); if let RelationBody::BoundaryExchange { items, .. } = &mut p.relations.get_mut(&boundary).unwrap().body { items.push(information); } p.relate( RelationKind::PortAllocation, "Vessel output represents report output", vessel_port, function_out, ); p.relate( RelationKind::PortAllocation, "System input represents assessment input", system_port, function_in, ); p.relate( RelationKind::ExchangeAllocation, "Report carried by connection", boundary, exchange, ); p.relate( RelationKind::InterfaceProvision, "Reporting service provided", vessel_port, interface, ); p.relate( RelationKind::InterfaceRequirement, "Reporting service required", system_port, interface, ); let sa_occurrence = occurrence( &mut p, chain, Layer::Sa, "Report handled", exchange, None, None, ); let scenario = add( &mut p, Kind::Scenario, Layer::Sa, "Repeated distress reports", None, ); *p.elements.get_mut(&scenario).unwrap().shared_mut().unwrap() = SharedBody::Scenario { viewpoint: ScenarioViewpoint::BoundaryInterface, context: Some(sa_cap), precondition: "A vessel has detected an emergency and the reporting service is available." .into(), postcondition: "The operator has a classified incident with the latest vessel report." .into(), steps: vec![], }; let vessel_line = add( &mut p, Kind::Lifeline, Layer::Sa, "Vessel service lifeline", Some(scenario), ); *p.elements .get_mut(&vessel_line) .unwrap() .shared_mut() .unwrap() = SharedBody::Lifeline { represented: Some(actor), }; let system_line = add( &mut p, Kind::Lifeline, Layer::Sa, "Coordination system lifeline", Some(scenario), ); *p.elements .get_mut(&system_line) .unwrap() .shared_mut() .unwrap() = SharedBody::Lifeline { represented: Some(system), }; occurrence( &mut p, scenario, Layer::Sa, "Initial distress report", exchange, Some(vessel_line), Some(system_line), ); let update = occurrence( &mut p, scenario, Layer::Sa, "Updated distress report", exchange, Some(vessel_line), Some(system_line), ); if let Some(SharedBody::Occurrence { precondition, postcondition, .. }) = p.elements.get_mut(&update).unwrap().shared_mut() { *precondition = "The vessel has more recent position information.".into(); *postcondition = "The incident position is refreshed without creating a second incident.".into(); } let machine = add( &mut p, Kind::StateMachine, Layer::Sa, "Reporting operation modes", Some(system), ); let region = add( &mut p, Kind::Region, Layer::Sa, "Reporting quality region", Some(machine), ); let initial = add( &mut p, Kind::Initial, Layer::Sa, "Start reporting", Some(region), ); let normal = add( &mut p, Kind::Mode, Layer::Sa, "Normal reporting", Some(region), ); let degraded = add( &mut p, Kind::Mode, Layer::Sa, "Degraded reporting", Some(region), ); p.relate( RelationKind::StateTransition, "Initialize reporting", initial, normal, ); let degrade = p.relate( RelationKind::StateTransition, "Signal degraded", normal, degraded, ); let timeout = add(&mut p, Kind::Event, Layer::Sa, "Report timeout", None); *p.elements.get_mut(&timeout).unwrap().shared_mut().unwrap() = SharedBody::Event { body: EventBody::Time { kind: TimeEventKind::After, expression: "30 s".into(), }, }; p.relations.get_mut(°rade).unwrap().body = RelationBody::StateTransition { source: normal, target: degraded, transition_kind: TransitionKind::External, triggers: vec![timeout], effects: vec![], trigger: "report_timeout".into(), guard: "seconds_since_last_report > 30".into(), effect: "Flag the incident and request an operator review.".into(), }; let restore = p.relate( RelationKind::StateTransition, "Signal restored", degraded, normal, ); let report_received = add( &mut p, Kind::Event, Layer::Sa, "Validated report received", None, ); *p.elements .get_mut(&report_received) .unwrap() .shared_mut() .unwrap() = SharedBody::Event { body: EventBody::Signal { items: vec![information], }, }; p.relations.get_mut(&restore).unwrap().body = RelationBody::StateTransition { source: degraded, target: normal, transition_kind: TransitionKind::External, triggers: vec![report_received], effects: vec![], trigger: "validated_report_received".into(), guard: "position_is_current".into(), effect: "Clear the degraded-reporting alert.".into(), }; p.relate( RelationKind::Availability, "Assessment in normal mode", coordinate, normal, ); p.relate( RelationKind::Availability, "Assessment in degraded mode", coordinate, degraded, ); let action = p.relate( RelationKind::StateAction, "Review on degraded entry", degraded, coordinate, ); p.relations.get_mut(&action).unwrap().body = RelationBody::StateAction { source: degraded, target: coordinate, phase: StateActionKind::Entry, }; let constraint = add( &mut p, Kind::Constraint, Layer::Sa, "Response time budget", None, ); *p.elements .get_mut(&constraint) .unwrap() .shared_mut() .unwrap() = SharedBody::Constraint { expression: "incident_alert_latency <= 120 s".into(), constrained: vec![coordinate, exchange], }; for (owner, name, uri, revision, relation) in [ ( coordinate, "Response implementation", "git+https://example.org/rescue/control?path=src/response.rs", "design-v2", ArtifactRelation::Implements, ), ( system, "Console enclosure CAD", "cad://rescue-console/enclosure.step", "B.3", ArtifactRelation::References, ), ] { let id = Id::new_v4(); let alias = p.fresh_alias(name, "artifact", id); p.artifact_links.insert(id,ArtifactLink{id,alias,name:name.into(),description:"Illustrative external engineering reference; opening a model does not fetch it.".into(),owner,relation,uri:uri.into(),revision:Some(revision.into()),fragment:None}); } for (oa, sa, kind) in [ (coordination, system, TraceKind::Participant), (vessel, actor, TraceKind::Participant), (oa_parent, sa_parent, TraceKind::Refinement), (report, transmit, TraceKind::Refinement), (assess, coordinate, TraceKind::Refinement), (oa_cap, sa_cap, TraceKind::Capability), (process, chain, TraceKind::Sequence), (oa_occurrence, sa_occurrence, TraceKind::Scenario), (interaction, exchange, TraceKind::Exchange), (oa_item, information, TraceKind::Item), ] { trace(&mut p, oa, sa, kind); } let oa_view = diagram( &mut p, Layer::Oa, ProjectionKind::Allocation, "OA participants and activities", &[coordination, vessel, report, assess], ); let sa_view = diagram( &mut p, Layer::Sa, ProjectionKind::Allocation, "SA system boundary and functions", &[system, actor, transmit, coordinate], ); let functions = diagram( &mut p, Layer::Sa, ProjectionKind::FunctionalDataflow, "SA functional decomposition", &[sa_parent, transmit, coordinate], ); let oa_capabilities = diagram( &mut p, Layer::Oa, ProjectionKind::Capabilities, "OA capabilities and participants", &[coordination, vessel, role, oa_cap], ); let sa_capabilities = diagram( &mut p, Layer::Sa, ProjectionKind::Capabilities, "SA missions and capabilities", &[system, actor, mission, sa_cap], ); let activities = diagram( &mut p, Layer::Oa, ProjectionKind::FunctionalDataflow, "OA activity dataflow", &[oa_parent, report, assess], ); execute_batch( &p, &[ Command::Layout(oa_view), Command::Layout(sa_view), Command::Layout(functions), Command::Layout(oa_capabilities), Command::Layout(sa_capabilities), Command::Layout(activities), ], ) .expect("The bundled OA/SA example is structurally valid") }