use std::sync::Arc;
use phoxal::api;
use phoxal::prelude::*;
#[derive(Clone)]
struct Grid {
width: u32,
height: u32,
resolution_m: f32,
cells: Vec<u8>,
}
impl Grid {
fn empty() -> Self {
Self {
width: 8,
height: 8,
resolution_m: 0.1,
cells: vec![255; 64],
}
}
fn response(&self) -> api::map::SubmapResponse {
api::map::SubmapResponse {
width: self.width,
height: self.height,
resolution_m: self.resolution_m,
cells: self.cells.clone(),
}
}
}
struct MapSnapshot {
grid: Arc<Grid>,
}
#[derive(serde::Deserialize, phoxal::Config)]
struct Config {}
#[derive(phoxal::Api)]
struct Api {
localize: Latest<api::localize::LocalizationState>,
revision: StatePublisher<api::map::Revision>,
get_asset: Server<api::asset::GetRequest, api::asset::GetResponse>,
submap: Server<api::map::SubmapRequest, api::map::SubmapResponse>,
}
#[phoxal::service(id = "snapshot-map")]
struct SnapshotMap {
grid: Arc<Grid>,
rev: u64,
}
#[phoxal::behavior]
impl SnapshotMap {
#[setup]
async fn setup(ctx: &mut SetupContext<Self>) -> Result<(Self, Self::Api)> {
Ok((
Self {
grid: Arc::new(Grid::empty()),
rev: 0,
},
Self::Api {
localize: ctx.latest(api::topic::client().localize().state()).await?,
revision: ctx
.state_publisher(api::topic::owner().map().revision())
.await?,
get_asset: ctx.server(api::topic::client().asset().get()).await?,
submap: ctx.server(api::topic::client().map().submap()).await?,
},
))
}
#[step(hz = 2)]
async fn step(&mut self, api: &mut Self::Api, step: StepContext) -> Result<()> {
if api.localize.latest().is_some() {
self.rev = self.rev.saturating_add(1);
}
api.revision.publish(
step.token(),
api::map::Revision {
revision: self.rev,
resolution_m: self.grid.resolution_m,
},
)?;
Ok(())
}
#[server(api = get_asset)]
async fn get_asset(
&mut self,
_api: &mut Self::Api,
request: api::asset::GetRequest,
) -> ServerResult<api::asset::GetResponse> {
self.rev = self.rev.saturating_add(1);
if request.path == "map.cells" {
Ok(api::asset::GetResponse::Found {
bytes: self.grid.cells.clone(),
})
} else {
Ok(api::asset::GetResponse::Missing)
}
}
#[server_snapshot(api = submap)]
async fn submap(
state: Snapshot<MapSnapshot>,
_api: &Self::Api,
_request: api::map::SubmapRequest,
) -> ServerResult<api::map::SubmapResponse> {
Ok(state.grid.response())
}
#[snapshot]
fn snapshot(&self) -> MapSnapshot {
MapSnapshot {
grid: Arc::clone(&self.grid),
}
}
}
fn main() -> phoxal::Result<()> {
phoxal::run::<SnapshotMap>()
}