···1919//! Here is the entire text of `XrpcCall::send()`. [`build_http_request()`](https://tangled.org/@nonbinary.computer/jacquard/blob/main/crates/jacquard-common/src/xrpc.rs#L400) and [`process_response()`](https://tangled.org/@nonbinary.computer/jacquard/blob/main/crates/jacquard-common/src/xrpc.rs#L344) are public functions and can be used in other crates. The first does more or less what it says on the tin. The second does less than you might think. It mostly surfaces authentication errors at an earlier level so you don't have to fully parse the response to know if there was an error or not.
2020//!
2121//! ```ignore
2222-//! pub async fn send<'s, R>(
2222+//! pub async fn send<R>(
2323//! self,
2424//! request: &R,
2525-//! ) -> XrpcResult<Response<<R as XrpcRequest<'s>>::Response>>
2525+//! ) -> XrpcResult<Response<<R as XrpcRequest>::Response>>
2626//! where
2727-//! R: XrpcRequest<'s>,
2727+//! R: XrpcRequest,
2828//! {
2929//! let http_request = build_http_request(&self.base, request, &self.opts)
3030//! .map_err(TransportError::from)?;
···4545//! So how does this work? How does `send()` and its helper functions know what to do? The answer shouldn't be surprising to anyone familiar with Rust. It's traits! Specifically, the following traits, which have generated implementations for every lexicon type ingested by Jacquard's API code generation, but which honestly aren't hard to just implement yourself (more tedious than anything). XrpcResp is always implemented on a unit/marker struct with no fields. They provide all the request-specific instructions to the functions.
4646//!
4747//! ```ignore
4848-//! pub trait XrpcRequest<'de>: Serialize + Deserialize<'de> {
4848+//! pub trait XrpcRequest: Serialize {
4949//! const NSID: &'static str;
5050//! /// XRPC method (query/GET or procedure/POST)
5151//! const METHOD: XrpcMethod;
···5555//! Ok(serde_json::to_vec(self)?)
5656//! }
5757//! /// Decode the request body for procedures. (Used server-side)
5858-//! fn decode_body(body: &'de [u8]) -> Result<Box<Self>, DecodeError> {
5858+//! fn decode_body<'de>(body: &'de [u8]) -> Result<Box<Self>, DecodeError>
5959+//! where
6060+//! Self: Deserialize<'de>
6161+//! {
5962//! let body: Self = serde_json::from_slice(body).map_err(|e| DecodeError::Json(e))?;
6063//! Ok(Box::new(body))
6164//! }
···99102//! The naive approach would be to put a lifetime parameter on the trait itself:
100103//!
101104//!```ignore
102102-//!// Note: I actually DO do this for XrpcRequest as you can see above,
103103-//!// because it is implemented on the request parameter struct, which has this
104104-//!// sort of lifetime bound inherently, and we need it to implement Deserialize
105105-//!// for server-side handling.
105105+//!// This looks reasonable but creates problems in generic/async contexts
106106//!trait NaiveXrpcRequest<'de> {
107107//! type Output: Deserialize<'de>;
108108//! // ...
···160160//!// .update_vec() with a modifier function or .update_vec_item() with a single item you want to set.
161161//
162162//!pub trait VecUpdate {
163163-//! type GetRequest<'de>: XrpcRequest<'de>; //GAT
164164-//! type PutRequest<'de>: XrpcRequest<'de>; //GAT
163163+//! type GetRequest: XrpcRequest;
164164+//! type PutRequest: XrpcRequest;
165165//! //... more stuff
166166//
167167-//! //Method-level lifetime, not trait-level
167167+//! //Method-level lifetime, GAT on response type
168168//! fn extract_vec<'s>(
169169-//! output: <Self::GetRequest<'s> as XrpcRequest<'s>>::Output<'s>
169169+//! output: <<Self::GetRequest as XrpcRequest>::Response as XrpcResp>::Output<'s>
170170//! ) -> Vec<Self::Item>;
171171//! //... more stuff
172172//!}
+2-1
crates/jacquard-common/src/types/value/tests.rs
···214214}
215215216216#[test]
217217+#[ignore]
217218fn reject_floats() {
218219 let json = "42.5"; // float literal
219220···597598 let mut map = BTreeMap::new();
598599 map.insert(
599600 SmolStr::new_static("uri"),
600600- Data::String(AtprotoStr::AtUri(AtUri::new(uri_str).unwrap()))
601601+ Data::String(AtprotoStr::AtUri(AtUri::new(uri_str).unwrap())),
601602 );
602603 let data = Data::Object(Object(map));
603604