1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! Reading a request's parameters.
//!
//! Three helpers, all of them turning a [`JsonObject`] the peer sent into
//! something typed enough to act on. They are free functions rather than
//! methods because nothing about them depends on which server is dispatching:
//! a `tools/call` params object is the same shape whoever is serving it.
//!
//! They live apart from the router because a JSON read that is wrong is a
//! different bug from a routing decision that is wrong, and `DispatchError` is
//! the only thing the two have in common.
use crateDispatchError;
use crateJsonObject;
/// Checks that `initialize` params are the shape the handshake has to be.
///
/// Every revision that has a handshake marks `capabilities`, `clientInfo` and
/// `protocolVersion` required on `InitializeRequestParams`, and `Implementation`
/// marks `name` and `version` required inside `clientInfo`. Each is read and
/// type-checked here, which is what "not a silently-ignored field" means: a
/// missing or misshapen required field is a refusal, not a default.
///
/// # Why this returns nothing
///
/// A check, not a parse, and the distinction is worth stating because the
/// crate's rule is to parse rather than validate. It returns nothing because
/// nothing in the answer comes from the request: `protocolVersion` is the
/// session's revision, `capabilities` is the session's profile, and
/// `serverInfo` is this server. The offer is a statement about the *client*,
/// and the layer that owns that is the one that negotiated the session — it
/// already holds the client's capability set and, on a `NegotiatedSession`,
/// the client's [`PeerInfo`]. Reading it again here to build a value nobody
/// consumes would be the second source of truth, not the first.
///
/// The one field whose parse *is* a decision: `protocolVersion` is run through
/// [`ProtocolVersion`]'s `FromStr`, so a client offering a revision this build
/// has never heard of — which the specification explicitly allows, and which
/// [`negotiate_server`] answers with the server's own version rather than an
/// error — still gets a session, while a string that is not a `YYYY-MM-DD`
/// date is a typo and is refused.
///
/// # Errors
///
/// Reads `name` and `arguments` out of a `tools/call` params object.
///
/// A missing `name` is a malformed request rather than an unknown tool: the
/// call named nothing at all, and reporting `UnknownTool` for it would send a
/// caller hunting for a tool that exists and works.
///
/// # Errors
///
/// [`DispatchError::MalformedParams`] when the body is not an object, when
/// `name` is absent or is not a string, and when `arguments` is present but is
/// not an object. `arguments` is optional — a tool taking no parameters is
/// called with none.
pub
/// The string member `key` of a params object.
pub
/// One member of a params object, already parsed.
///
/// `None` for an absent member as well as `null`, because both mean the same
/// thing to every caller here and the specification's params are optional
/// throughout. A non-object params document is malformed either way.
pub