use crate::types::basic::{Boolean, OSString, ParameterDeclarations, Value};
use crate::types::catalogs::references::ControllerCatalogReference;
use crate::types::distributions::ParameterValueDistribution;
use crate::types::entities::vehicle::{File, Properties, Property};
use crate::types::enums::ControllerType;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[derive(Default)]
pub struct ParameterAssignments {
pub assignments: Vec<ParameterAssignment>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ParameterAssignment {
pub parameter_ref: OSString,
pub value: OSString,
}
impl Default for ParameterAssignment {
fn default() -> Self {
Self {
parameter_ref: Value::Literal("defaultParam".to_string()),
value: Value::Literal("defaultValue".to_string()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Directory {
pub path: OSString,
}
impl Default for Directory {
fn default() -> Self {
Self {
path: Value::Literal("./".to_string()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Controller {
#[serde(rename = "@name")]
pub name: OSString,
#[serde(rename = "@controllerType", skip_serializing_if = "Option::is_none")]
pub controller_type: Option<ControllerType>,
#[serde(
rename = "ParameterDeclarations",
skip_serializing_if = "Option::is_none"
)]
pub parameter_declarations: Option<ParameterDeclarations>,
#[serde(rename = "Properties", skip_serializing_if = "Option::is_none")]
pub properties: Option<Properties>,
}
impl Default for Controller {
fn default() -> Self {
Self {
name: Value::Literal("DefaultController".to_string()),
controller_type: Some(ControllerType::Movement),
parameter_declarations: None,
properties: None,
}
}
}
#[derive(Debug, Clone, Serialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ObjectController {
#[serde(rename = "@name", skip_serializing_if = "Option::is_none")]
pub name: Option<OSString>,
#[serde(rename = "Controller", skip_serializing_if = "Option::is_none")]
pub controller: Option<Controller>,
#[serde(rename = "CatalogReference", skip_serializing_if = "Option::is_none")]
pub catalog_reference: Option<ControllerCatalogReference>,
}
impl<'de> Deserialize<'de> for ObjectController {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{self, MapAccess, Visitor};
use std::fmt;
#[derive(Deserialize)]
#[serde(field_identifier)]
enum Field {
#[serde(rename = "@name")]
Name,
#[serde(rename = "Controller")]
Controller,
#[serde(rename = "CatalogReference")]
CatalogReference,
}
struct ObjectControllerVisitor;
impl<'de> Visitor<'de> for ObjectControllerVisitor {
type Value = ObjectController;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct ObjectController")
}
fn visit_map<V>(self, mut map: V) -> std::result::Result<ObjectController, V::Error>
where
V: MapAccess<'de>,
{
let mut name = None;
let mut controller = None;
let mut catalog_reference = None;
while let Some(key) = map.next_key()? {
match key {
Field::Name => {
if name.is_some() {
return Err(de::Error::duplicate_field("name"));
}
name = Some(map.next_value()?);
}
Field::Controller => {
if controller.is_some() {
return Err(de::Error::duplicate_field("Controller"));
}
controller = Some(map.next_value()?);
}
Field::CatalogReference => {
if catalog_reference.is_some() {
return Err(de::Error::duplicate_field("CatalogReference"));
}
catalog_reference = Some(map.next_value()?);
}
}
}
match (controller.is_some(), catalog_reference.is_some()) {
(true, false) | (false, true) | (false, false) => {
Ok(ObjectController {
name,
controller,
catalog_reference,
})
}
(true, true) => Err(de::Error::custom(
"ObjectController must contain exactly one of Controller or CatalogReference, found both"
)),
}
}
}
const FIELDS: &[&str] = &["@name", "Controller", "CatalogReference"];
deserializer.deserialize_struct("ObjectController", FIELDS, ObjectControllerVisitor)
}
}
impl Default for ObjectController {
fn default() -> Self {
Self {
name: None,
controller: Some(Controller::default()),
catalog_reference: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
#[derive(Default)]
pub struct ControllerProperties {
#[serde(rename = "Property")]
pub properties: Vec<Property>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ActivateControllerAction {
#[serde(rename = "@controllerRef")]
pub controller_ref: OSString,
#[serde(
rename = "ParameterAssignments",
skip_serializing_if = "Option::is_none"
)]
pub parameter_assignments: Option<ParameterAssignments>,
}
impl Default for ActivateControllerAction {
fn default() -> Self {
Self {
controller_ref: Value::Literal("DefaultController".to_string()),
parameter_assignments: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct OverrideControllerValueAction {
#[serde(rename = "@controllerRef")]
pub controller_ref: OSString,
#[serde(rename = "ParameterAssignments")]
pub parameter_assignments: ParameterAssignments,
#[serde(rename = "@active")]
pub active: Boolean,
}
impl Default for OverrideControllerValueAction {
fn default() -> Self {
Self {
controller_ref: Value::Literal("DefaultController".to_string()),
parameter_assignments: ParameterAssignments::default(),
active: Value::Literal(true),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ControllerAssignment {
#[serde(rename = "@controllerRef")]
pub controller_ref: OSString,
#[serde(rename = "@targetEntity")]
pub target_entity: OSString,
}
impl Default for ControllerAssignment {
fn default() -> Self {
Self {
controller_ref: Value::Literal("DefaultController".to_string()),
target_entity: Value::Literal("Ego".to_string()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
#[derive(Default)]
pub struct ControllerCatalogLocation {
#[serde(rename = "Directory")]
pub directory: Directory,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ControllerDistribution {
#[serde(rename = "@controllerType")]
pub controller_type: ControllerType,
#[serde(rename = "ParameterValueDistribution")]
pub distribution: ParameterValueDistribution,
}
impl Default for ControllerDistribution {
fn default() -> Self {
use crate::types::distributions::deterministic::*;
let single_param_dist = DeterministicSingleParameterDistribution {
parameter_name: Value::Literal("controllerParam".to_string()),
distribution_set: Some(DistributionSet {
elements: vec![DistributionSetElement {
value: Value::Literal("default".to_string()),
}],
}),
distribution_range: None,
user_defined_distribution: None,
};
let deterministic = crate::types::distributions::Deterministic {
single_distributions: vec![single_param_dist],
multi_distributions: vec![],
};
Self {
controller_type: ControllerType::Movement,
distribution: ParameterValueDistribution::new_deterministic(
File {
filepath: "default.xosc".to_string(),
},
deterministic,
),
}
}
}
impl Controller {
pub fn new(name: String, controller_type: ControllerType) -> Self {
Self {
name: Value::Literal(name),
controller_type: Some(controller_type),
parameter_declarations: None,
properties: None,
}
}
pub fn with_parameters(
name: String,
controller_type: ControllerType,
parameters: ParameterDeclarations,
) -> Self {
Self {
name: Value::Literal(name),
controller_type: Some(controller_type),
parameter_declarations: Some(parameters),
properties: None,
}
}
pub fn with_properties(
name: String,
controller_type: ControllerType,
properties: Properties,
) -> Self {
Self {
name: Value::Literal(name),
controller_type: Some(controller_type),
parameter_declarations: None,
properties: Some(properties),
}
}
}
impl ObjectController {
pub fn with_controller(controller: Controller) -> Self {
Self {
name: None,
controller: Some(controller),
catalog_reference: None,
}
}
pub fn with_catalog_reference(catalog_reference: ControllerCatalogReference) -> Self {
Self {
name: None,
controller: None,
catalog_reference: Some(catalog_reference),
}
}
pub fn with_named_controller(name: String, controller: Controller) -> Self {
Self {
name: Some(Value::Literal(name)),
controller: Some(controller),
catalog_reference: None,
}
}
pub fn with_named_catalog_reference(
name: String,
catalog_reference: ControllerCatalogReference,
) -> Self {
Self {
name: Some(Value::Literal(name)),
controller: None,
catalog_reference: Some(catalog_reference),
}
}
pub fn validate(&self) -> Result<(), String> {
match (self.controller.is_some(), self.catalog_reference.is_some()) {
(true, false) | (false, true) | (false, false) => Ok(()),
(true, true) => Err("ObjectController must contain at most one of Controller or CatalogReference, found both".to_string()),
}
}
pub fn validate_strict(&self) -> Result<(), String> {
match (self.controller.is_some(), self.catalog_reference.is_some()) {
(true, false) | (false, true) => Ok(()),
(true, true) => Err("ObjectController must contain exactly one of Controller or CatalogReference, found both".to_string()),
(false, false) => Err("ObjectController must contain exactly one of Controller or CatalogReference, found neither".to_string()),
}
}
}
impl ActivateControllerAction {
pub fn new(controller_ref: String) -> Self {
Self {
controller_ref: Value::Literal(controller_ref),
parameter_assignments: None,
}
}
pub fn with_parameters(
controller_ref: String,
parameter_assignments: ParameterAssignments,
) -> Self {
Self {
controller_ref: Value::Literal(controller_ref),
parameter_assignments: Some(parameter_assignments),
}
}
}
impl OverrideControllerValueAction {
pub fn new(
controller_ref: String,
parameter_assignments: ParameterAssignments,
active: bool,
) -> Self {
Self {
controller_ref: Value::Literal(controller_ref),
parameter_assignments,
active: Value::Literal(active),
}
}
}
impl ControllerAssignment {
pub fn new(controller_ref: String, target_entity: String) -> Self {
Self {
controller_ref: Value::Literal(controller_ref),
target_entity: Value::Literal(target_entity),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::enums::ControllerType;
#[test]
fn test_controller_creation() {
let controller = Controller::new("TestController".to_string(), ControllerType::Movement);
assert_eq!(controller.name.as_literal().unwrap(), "TestController");
assert_eq!(controller.controller_type, Some(ControllerType::Movement));
}
#[test]
fn test_object_controller_with_direct_controller() {
let controller = Controller::new("DirectController".to_string(), ControllerType::Lateral);
let object_controller = ObjectController::with_controller(controller);
assert!(object_controller.controller.is_some());
assert!(object_controller.catalog_reference.is_none());
}
#[test]
fn test_activate_controller_action() {
let action = ActivateControllerAction::new("MainController".to_string());
assert_eq!(
action.controller_ref.as_literal().unwrap(),
"MainController"
);
assert!(action.parameter_assignments.is_none());
}
#[test]
fn test_override_controller_action() {
let assignments = ParameterAssignments::default();
let action =
OverrideControllerValueAction::new("TestController".to_string(), assignments, true);
assert_eq!(
action.controller_ref.as_literal().unwrap(),
"TestController"
);
assert_eq!(action.active.as_literal().unwrap(), &true);
}
#[test]
fn test_controller_assignment() {
let assignment =
ControllerAssignment::new("AIController".to_string(), "Vehicle1".to_string());
assert_eq!(
assignment.controller_ref.as_literal().unwrap(),
"AIController"
);
assert_eq!(assignment.target_entity.as_literal().unwrap(), "Vehicle1");
}
#[test]
fn test_controller_serialization() {
let controller = Controller::new("SerializationTest".to_string(), ControllerType::Movement);
let xml = quick_xml::se::to_string(&controller).unwrap();
assert!(xml.contains("SerializationTest"));
assert!(xml.contains("movement"));
let deserialized: Controller = quick_xml::de::from_str(&xml).unwrap();
assert_eq!(controller, deserialized);
}
#[test]
fn test_controller_distribution() {
let distribution = ControllerDistribution::default();
assert_eq!(distribution.controller_type, ControllerType::Movement);
assert!(matches!(
distribution.distribution,
ParameterValueDistribution { .. }
));
}
#[test]
fn test_controller_properties() {
let mut properties = ControllerProperties::default();
let property = Property {
name: "testProp".to_string(),
value: "testValue".to_string(),
};
properties.properties.push(property);
assert_eq!(properties.properties.len(), 1);
}
#[test]
fn test_controller_defaults() {
let controller = Controller::default();
let object_controller = ObjectController::default();
let properties = ControllerProperties::default();
let activate_action = ActivateControllerAction::default();
let override_action = OverrideControllerValueAction::default();
let assignment = ControllerAssignment::default();
assert!(controller.name.as_literal().is_some());
assert!(object_controller.controller.is_some());
assert!(properties.properties.is_empty());
assert!(activate_action.controller_ref.as_literal().is_some());
assert!(override_action.active.as_literal().is_some());
assert!(assignment.target_entity.as_literal().is_some());
}
#[test]
fn test_object_controller_validation() {
let valid_direct = ObjectController {
name: None,
controller: Some(Controller::default()),
catalog_reference: None,
};
assert!(valid_direct.validate().is_ok());
let valid_catalog = ObjectController {
name: None,
controller: None,
catalog_reference: Some(ControllerCatalogReference::new(
"catalog".to_string(),
"entry".to_string(),
)),
};
assert!(valid_catalog.validate().is_ok());
let empty_controller = ObjectController {
name: None,
controller: None,
catalog_reference: None,
};
assert!(empty_controller.validate().is_ok());
assert!(empty_controller.validate_strict().is_err());
let invalid_both = ObjectController {
name: None,
controller: Some(Controller::default()),
catalog_reference: Some(ControllerCatalogReference::new(
"catalog".to_string(),
"entry".to_string(),
)),
};
assert!(invalid_both.validate().is_err());
let named_controller = ObjectController::with_named_controller(
"TestController".to_string(),
Controller::default(),
);
assert!(named_controller.validate().is_ok());
assert_eq!(
named_controller
.name
.as_ref()
.unwrap()
.as_literal()
.unwrap(),
"TestController"
);
}
}