use crate::types::basic::OSString;
use crate::types::controllers::ObjectController;
use serde::{Deserialize, Serialize};
pub mod axles;
pub mod pedestrian;
pub mod selection;
pub mod vehicle;
pub use axles::{Axle, Axles};
pub use pedestrian::Pedestrian;
pub use selection::{
ByName, ByObjectType, ByType, EntityDistribution, EntityDistributionEntry, EntitySelection,
ExternalObjectReference, ScenarioObjectTemplate, SelectedEntities, TemplateProperties,
TemplateProperty,
};
pub use vehicle::{Properties, Vehicle};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub enum EntityObject {
Vehicle(Box<Vehicle>),
Pedestrian(Box<Pedestrian>),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ScenarioEntityReference {
Vehicle(
crate::types::catalogs::references::CatalogReference<
crate::types::catalogs::entities::CatalogVehicle,
>,
),
Pedestrian(
crate::types::catalogs::references::CatalogReference<
crate::types::catalogs::entities::CatalogPedestrian,
>,
),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ScenarioObject {
#[serde(rename = "@name")]
pub name: OSString,
#[serde(rename = "Vehicle", skip_serializing_if = "Option::is_none")]
pub vehicle: Option<Vehicle>,
#[serde(rename = "Pedestrian", skip_serializing_if = "Option::is_none")]
pub pedestrian: Option<Pedestrian>,
#[serde(rename = "CatalogReference", skip_serializing_if = "Option::is_none")]
pub entity_catalog_reference: Option<ScenarioEntityReference>,
#[serde(rename = "ObjectController", skip_serializing_if = "Option::is_none")]
pub object_controller: Option<ObjectController>,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Entities {
#[serde(rename = "ScenarioObject", default)]
pub scenario_objects: Vec<ScenarioObject>,
}
impl ScenarioObject {
pub fn new_vehicle(name: String, vehicle: Vehicle) -> Self {
Self {
name: crate::types::basic::Value::literal(name),
vehicle: Some(vehicle),
pedestrian: None,
entity_catalog_reference: None,
object_controller: Some(ObjectController::default()),
}
}
pub fn new_pedestrian(name: String, pedestrian: Pedestrian) -> Self {
Self {
name: crate::types::basic::Value::literal(name),
vehicle: None,
pedestrian: Some(pedestrian),
entity_catalog_reference: None,
object_controller: Some(ObjectController::default()),
}
}
pub fn new_vehicle_catalog_reference(
name: String,
catalog_reference: crate::types::catalogs::references::CatalogReference<
crate::types::catalogs::entities::CatalogVehicle,
>,
) -> Self {
Self {
name: crate::types::basic::Value::literal(name),
vehicle: None,
pedestrian: None,
entity_catalog_reference: Some(ScenarioEntityReference::Vehicle(catalog_reference)),
object_controller: Some(ObjectController::default()),
}
}
pub fn new_pedestrian_catalog_reference(
name: String,
catalog_reference: crate::types::catalogs::references::CatalogReference<
crate::types::catalogs::entities::CatalogPedestrian,
>,
) -> Self {
Self {
name: crate::types::basic::Value::literal(name),
vehicle: None,
pedestrian: None,
entity_catalog_reference: Some(ScenarioEntityReference::Pedestrian(catalog_reference)),
object_controller: Some(ObjectController::default()),
}
}
pub fn vehicle_catalog_reference(
&self,
) -> Option<
&crate::types::catalogs::references::CatalogReference<
crate::types::catalogs::entities::CatalogVehicle,
>,
> {
match &self.entity_catalog_reference {
Some(ScenarioEntityReference::Vehicle(r)) => Some(r),
_ => None,
}
}
pub fn pedestrian_catalog_reference(
&self,
) -> Option<
&crate::types::catalogs::references::CatalogReference<
crate::types::catalogs::entities::CatalogPedestrian,
>,
> {
match &self.entity_catalog_reference {
Some(ScenarioEntityReference::Pedestrian(r)) => Some(r),
_ => None,
}
}
pub fn get_entity_object(&self) -> Option<EntityObject> {
if let Some(vehicle) = &self.vehicle {
Some(EntityObject::Vehicle(Box::new(vehicle.clone())))
} else {
self.pedestrian
.as_ref()
.map(|pedestrian| EntityObject::Pedestrian(Box::new(pedestrian.clone())))
}
}
pub fn get_name(&self) -> Option<&str> {
self.name.as_literal().map(|s| s.as_str())
}
}
impl Entities {
pub fn new() -> Self {
Self::default()
}
pub fn add_object(&mut self, object: ScenarioObject) {
self.scenario_objects.push(object);
}
pub fn find_object(&self, name: &str) -> Option<&ScenarioObject> {
self.scenario_objects
.iter()
.find(|obj| obj.get_name() == Some(name))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_scenario_object_creation() {
let vehicle = Vehicle::default();
let obj = ScenarioObject::new_vehicle("TestVehicle".to_string(), vehicle);
assert_eq!(obj.get_name(), Some("TestVehicle"));
assert!(obj.vehicle.is_some());
assert!(obj.pedestrian.is_none());
if let Some(v) = &obj.vehicle {
assert_eq!(v.name.as_literal().unwrap(), "DefaultVehicle");
}
match obj.get_entity_object() {
Some(EntityObject::Vehicle(v)) => {
assert_eq!(v.name.as_literal().unwrap(), "DefaultVehicle");
}
_ => panic!("Expected vehicle"),
}
}
#[test]
fn test_entities_container() {
let mut entities = Entities::new();
let vehicle = Vehicle::default();
let obj = ScenarioObject::new_vehicle("TestVehicle".to_string(), vehicle);
entities.add_object(obj);
assert_eq!(entities.scenario_objects.len(), 1);
let found = entities.find_object("TestVehicle");
assert!(found.is_some());
assert_eq!(found.unwrap().get_name(), Some("TestVehicle"));
let not_found = entities.find_object("NonExistent");
assert!(not_found.is_none());
}
#[test]
fn test_entities_serialization() {
let mut entities = Entities::new();
let vehicle = Vehicle::default();
let obj = ScenarioObject::new_vehicle("TestVehicle".to_string(), vehicle);
entities.add_object(obj);
let xml = quick_xml::se::to_string(&entities).unwrap();
assert!(xml.contains("ScenarioObject"));
assert!(xml.contains("name=\"TestVehicle\""));
}
}