use crate::identity::{ExecutionId, ParticipantId, ProducerId, TimelineId};
use serde::{Deserialize, Serialize};
use zenoh::key_expr::KeyExpr;
use zenoh::sample::{Sample, SampleBuilder};
use crate::bus::abi::CodecId;
use crate::bus::contract::{Endpoint, TestFamily};
use crate::bus::handle::stamp::StepToken;
use crate::bus::metadata::{BusMetadata, ParticipantSourceIdentity, SourceAttribution};
use crate::bus::session::BusConfig;
use crate::bus::time::{RobotInstant, TimeWindow};
use crate::bus::tree::BoundEndpoint;
pub(crate) fn bound<E: Endpoint>(key: &str) -> BoundEndpoint<E> {
BoundEndpoint::new(key.to_owned())
}
pub(crate) const TARGET_TOPIC: &str = "yTEST/drive/target";
pub(crate) const MANUAL_TOPIC: &str = "yTEST/motion/manual";
pub(crate) const GET_TOPIC: &str = "yTEST/asset/get";
#[derive(phoxal_macros::DescribeWire, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct Target {
pub(crate) linear_x_mps: f32,
pub(crate) angular_z_radps: f32,
}
impl crate::bus::contract::sealed::Endpoint for Target {}
impl Endpoint for Target {
type Family = TestFamily;
type Semantics = crate::bus::State;
}
#[derive(phoxal_macros::DescribeWire, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct Manual {
pub(crate) linear_x_mps: f32,
}
impl crate::bus::contract::sealed::Endpoint for Manual {}
impl Endpoint for Manual {
type Family = TestFamily;
type Semantics = crate::bus::Setpoint;
}
#[derive(phoxal_macros::DescribeWire, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct GetRequest {
pub(crate) path: String,
}
#[derive(phoxal_macros::DescribeWire, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) enum GetResponse {
Found { bytes: Vec<u8> },
Missing,
}
impl crate::bus::contract::sealed::Endpoint for GetRequest {}
impl Endpoint for GetRequest {
type Family = TestFamily;
type Semantics = crate::bus::Query;
}
impl crate::bus::contract::QueryEndpoint for GetRequest {
type Response = GetResponse;
}
pub(crate) fn timeline(value: u64) -> TimelineId {
TimelineId::from_raw(value).expect("a test timeline id is nonzero")
}
pub(crate) fn producer(value: u128) -> ProducerId {
ProducerId::try_from((1_u128 << 124) | value).expect("a test producer is canonical")
}
pub(crate) fn participant_config(participant: impl Into<String>) -> BusConfig {
BusConfig::for_participant(
ExecutionId::mint(),
ParticipantId::new(participant).expect("valid test participant"),
Vec::new(),
)
}
pub(crate) fn step(line: u64, ticks: u64) -> StepToken {
StepToken::mint(RobotInstant::new(timeline(line), ticks))
}
pub(crate) fn metadata() -> BusMetadata {
BusMetadata {
codec: CodecId::MessagePack.as_u8(),
sequence: 7,
stream_position: None,
produced_at: Some(TimeWindow::exact(RobotInstant::new(timeline(1), 42))),
source: SourceAttribution::Participant(ParticipantSourceIdentity::new(
crate::identity::ParticipantId::new("tester").expect("test participant"),
producer(1),
)),
}
}
pub(crate) fn sample_with(codec: u8, payload: Vec<u8>) -> Sample {
let encoding = if codec == CodecId::MessagePack.as_u8() {
CodecId::MessagePack.encoding_string()
} else {
format!("phoxal/v0;codec={codec}")
};
sample_with_encoding(codec, encoding, payload)
}
pub(crate) fn sample_with_encoding(codec: u8, encoding: String, payload: Vec<u8>) -> Sample {
let mut meta = metadata();
meta.codec = codec;
let key: KeyExpr<'static> =
KeyExpr::try_from("phoxal/dead/yTEST/drive/target").expect("a legal test key");
SampleBuilder::put(key, payload)
.encoding(encoding)
.attachment(meta.encode().expect("test metadata encodes"))
.into()
}
pub(crate) fn sample(codec: u8) -> Sample {
let payload = rmp_serde::to_vec_named(&Target {
linear_x_mps: 1.0,
angular_z_radps: 0.5,
})
.expect("a test body encodes");
sample_with(codec, payload)
}