mod.rsannotatedmod.rssource67 lines · 2.8 KB · raw

One file per family of routes. Each route is a type that says, in its Route impl, which capabilities it needs; the service serves it only for an adapter that has them (see crate::Service::serve).

4mod jev;
5mod journal;
6mod messages;
7mod pictures;
8mod speak;
9mod sync;
10mod usage;
12use crate::Response;
13
14pub use jev::{Check, Embed, Rerank};
15pub use journal::Journal;
16pub use messages::Messages;
17pub use pictures::Pictures;
18pub use speak::Speak;
19pub use sync::{ChatSync, HouseholdSync, MemorySync};
20pub use usage::Usage;
21
22mod sealed {
23    pub trait Sealed {}
24}

A route, or a family of routes that share their work, and what it takes to serve it.

impl<C: HasJudge + HasClock> Route<C> for Check is the whole statement of what /check needs: a service on an adapter without those capabilities cannot be given the route, so cannot answer it. The trait is sealed; a route is added to this crate, with its laws in whiskers-conformance and its capability in whiskers-ports.

32#[expect(async_fn_in_trait, reason = "a Worker's futures hold JavaScript values and cannot be Send, so no Send bound may be required here")]
33pub trait Route<C>: sealed::Sealed {

The paths this route answers. Routes do not share a path.

35    const PATHS: &'static [&'static str];

Answers a request for one of PATHS, which the service has already found to be a readable POST.

38    async fn answer(&self, adapter: &C, path: &str, body: &str) -> Response;
39}

The routes a service has been given: built by [crate::Service::serve], never written out.

42#[expect(async_fn_in_trait, reason = "a Worker's futures hold JavaScript values and cannot be Send, so no Send bound may be required here")]
43pub trait Routes<C> {

The response of the route that answers path, or None if no route given to the service does.

45    async fn dispatch(&self, adapter: &C, path: &str, body: &str) -> Option<Response>;
46}
48impl<C> Routes<C> for () {
49    async fn dispatch(&self, _: &C, _: &str, _: &str) -> Option<Response> {
50        None
51    }
52}

A route given to the service, and the routes given before it.

55pub struct Then<R, Rest>(pub(crate) R, pub(crate) Rest);
57impl<C, R: Route<C>, Rest: Routes<C>> Routes<C> for Then<R, Rest> {
58    async fn dispatch(&self, adapter: &C, path: &str, body: &str) -> Option<Response> {
59        if R::PATHS.contains(&path) { Some(self.0.answer(adapter, path, body).await) } else { self.1.dispatch(adapter, path, body).await }
60    }
61}

Why a body did not parse, without a word of it: serde's own message quotes the offending value (invalid type: string "..."), and a body here is what a child said or what Whiskers remembers.

65pub(crate) fn kind_of(e: &serde_json::Error) -> String {
66    format!("{:?} at line {} column {}", e.classify(), e.line(), e.column())
67}