pub trait AnswerSet: Sized {
// Required method
fn deserialize_answers<'de, D>(
deserializer: D,
context: AnswerContext,
) -> Result<Self, D::Error>
where D: Deserializer<'de>;
}Expand description
A type the answers object of a response decodes into.
Answers implements it as a lookup by question name. A question set
declared as a struct implements it by reading each answer into the field of
the same name, which needs no map and no name string at all: the struct’s
visitor matches the key and hands the value to NoulAnswer,
ChoiceAnswer or ScoreAnswer, whose Deserialize implementations
are the same single-pass readers Answers uses, fixed to one kind.
§Contract
Every implementation, written by hand or generated, keeps these rules;
Answers and the struct example below keep them, and the tests of this
module hold both to them.
- Input. The deserializer yields exactly one JSON object, keyed by
question name. Anything else (an array, a string,
null) is an error atanswers. - Order. The members of that object may arrive in any order, and inside
one answer
typemay arrive after the members it governs. What a successful decode yields does not depend on either order, except which of two answers with one name is kept: the first in wire order, as the repeated-answer rule says. Which path a failure names can depend on order, as the next two rules say. - Wrong kind. An answer whose
typeis not the kind the field holds - including an answer that is not an object at all, or has notype- is an error atanswers.<field>.typewhenevertypecomes before the members of the field’s kind, which is the order the API writes. A typed field knows its kind beforetypearrives and reads those members as they come, so when a misshaped member of the field’s kind precedes a wrongtype, the error is reported at that member,answers.<field>.<member>. - Wrong shape. A member of the right kind with the wrong shape is an
error at
answers.<field>.<member>when the kind is known as the member arrives: always for a typed field, and forAnswerswhentypecame first.Answersholds a member that arrives beforetypeas raw text and checks it once the type is known, after the walk has left it, so it reports that failure atanswers.<field>. - Two types. An answer that names
typetwice with two different values is an error atanswers.<field>.type, whichever members it carries; naming the same type twice is accepted. (Upstream lets the lasttypewin; an answer that contradicts itself is refused here instead.) - Repeated answer. When the object names one question twice, the first
answer is the one the set holds. A struct keeps its field’s first answer
and skips a later answer of the same name unread, as it skips an extra
answer, so the later one’s kind and shape do not matter.
Answerskeeps every answer it reads, in wire order, and every lookup returns the first of them; it reads a later answer like any other, so one of the wrong shape is still an error there. A body both accept gives both the same answer. - Missing answer. A field with no answer is an error at
answers.<field>, where<field>is the question’s wire name (whatmissing_fieldreceives), not the Rust field’s identifier. A response with noanswersmember at all is an error atanswersfor every set that cannot be empty: the method is then called with an empty object, and whatever it fails with is reported as the missing member. A set that can be empty, asAnswerscan, decodes to its empty value. - Extra answers. An answer the type has no field for is skipped unread,
whatever its kind or shape, and is never an error. It stays in the raw
body.
Answerskeeps every answer of a kind this version models and skips the others the same way. - Allocation. Nothing is allocated beyond the storage of the fields
themselves: keys are matched where they lie, never copied into a
String, and no intermediate map or value tree is built. - Context. The
AnswerContextis a sizing hint. An implementation may use it or ignore it, and the result is the same either way.
A type that does not implement the trait is refused where a response of it is asked for:
use typesafe_sdk::de::AnswerSet;
fn decode_into<A: AnswerSet>() {}
decode_into::<String>();An implementation for a struct of three answers looks like this. The key is matched by a field identifier whose visitor only compares the text, so a key written with escapes works and no key is copied:
use std::fmt;
use serde::de::{self, Deserialize, Deserializer, IgnoredAny, MapAccess, Visitor};
use typesafe_sdk::{
de::{AnswerContext, AnswerSet},
response::{ChoiceAnswer, NoulAnswer, ScoreAnswer},
};
struct Ticket {
spam: NoulAnswer,
tone: ChoiceAnswer,
quality: ScoreAnswer,
}
enum Field {
Spam,
Tone,
Quality,
Other,
}
impl AnswerSet for Ticket {
fn deserialize_answers<'de, D>(deserializer: D, _: AnswerContext) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct TicketVisitor;
impl<'de> Visitor<'de> for TicketVisitor {
type Value = Ticket;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("the answers of a Ticket")
}
fn visit_map<M>(self, mut map: M) -> Result<Ticket, M::Error>
where
M: MapAccess<'de>,
{
let (mut spam, mut tone, mut quality) = (None, None, None);
while let Some(field) = map.next_key::<Field>()? {
match field {
Field::Spam if spam.is_none() => spam = Some(map.next_value()?),
Field::Tone if tone.is_none() => tone = Some(map.next_value()?),
Field::Quality if quality.is_none() => {
quality = Some(map.next_value()?);
}
// An answer the struct has no field for, or a
// later answer to a question already read: the
// first answer of a name is the one kept.
_ => {
map.next_value::<IgnoredAny>()?;
}
}
}
Ok(Ticket {
spam: spam.ok_or_else(|| de::Error::missing_field("spam"))?,
tone: tone.ok_or_else(|| de::Error::missing_field("tone"))?,
quality: quality.ok_or_else(|| de::Error::missing_field("quality"))?,
})
}
}
deserializer.deserialize_map(TicketVisitor)
}
}Required Methods§
Sourcefn deserialize_answers<'de, D>(
deserializer: D,
context: AnswerContext,
) -> Result<Self, D::Error>where
D: Deserializer<'de>,
fn deserialize_answers<'de, D>(
deserializer: D,
context: AnswerContext,
) -> Result<Self, D::Error>where
D: Deserializer<'de>,
Reads the answers object of a response.
When a response carries no answers member at all, this is called with
a deserializer of an empty object. An implementation that holds
required answers fails there in the usual way, and the decoder reports
that failure as the missing answers member.
§Errors
Returns the deserializer’s error when an answer is missing, is of the wrong kind, or does not have the shape its kind requires.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".