]> git.proxmox.com Git - rustc.git/blame - vendor/gix-protocol/src/fetch/delegate.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / vendor / gix-protocol / src / fetch / delegate.rs
CommitLineData
0a29b90c
FG
1use std::{
2 borrow::Cow,
3 io,
4 ops::{Deref, DerefMut},
5};
6
7use bstr::BString;
8use gix_transport::client::Capabilities;
9
10use crate::{
11 fetch::{Arguments, Response},
12 handshake::Ref,
13};
14
15/// Defines what to do next after certain [`Delegate`] operations.
16#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
17pub enum Action {
18 /// Continue the typical flow of operations in this flow.
19 Continue,
20 /// Return at the next possible opportunity without making further requests, possibly after closing the connection.
21 Cancel,
22}
23
24/// The non-IO protocol delegate is the bare minimal interface needed to fully control the [`fetch`][crate::fetch()] operation, sparing
25/// the IO parts.
26/// Async implementations must treat it as blocking and unblock it by evaluating it elsewhere.
27///
28/// See [Delegate] for the complete trait.
29pub trait DelegateBlocking {
30 /// Return extra parameters to be provided during the handshake.
31 ///
32 /// Note that this method is only called once and the result is reused during subsequent handshakes which may happen
33 /// if there is an authentication failure.
34 fn handshake_extra_parameters(&self) -> Vec<(String, Option<String>)> {
35 Vec::new()
36 }
37 /// Called before invoking 'ls-refs' on the server to allow providing it with additional `arguments` and to enable `features`.
38 /// If the server `capabilities` don't match the requirements abort with an error to abort the entire fetch operation.
39 ///
40 /// Note that some arguments are preset based on typical use, and `features` are preset to maximize options.
41 /// The `server` capabilities can be used to see which additional capabilities the server supports as per the handshake which happened prior.
42 ///
43 /// If the delegate returns [`ls_refs::Action::Skip`], no 'ls-refs` command is sent to the server.
44 ///
45 /// Note that this is called only if we are using protocol version 2.
46 fn prepare_ls_refs(
47 &mut self,
48 _server: &Capabilities,
49 _arguments: &mut Vec<BString>,
50 _features: &mut Vec<(&str, Option<Cow<'_, str>>)>,
51 ) -> std::io::Result<ls_refs::Action> {
52 Ok(ls_refs::Action::Continue)
53 }
54
55 /// Called before invoking the 'fetch' interaction with `features` pre-filled for typical use
56 /// and to maximize capabilities to allow aborting an interaction early.
57 ///
58 /// `refs` is a list of known references on the remote based on the handshake or a prior call to ls_refs.
59 /// These can be used to abort early in case the refs are already known here.
60 ///
61 /// As there will be another call allowing to post arguments conveniently in the correct format, i.e. `want hex-oid`,
62 /// there is no way to set arguments at this time.
63 ///
64 /// `version` is the actually supported version as reported by the server, which is relevant in case the server requested a downgrade.
65 /// `server` capabilities is a list of features the server supports for your information, along with enabled `features` that the server knows about.
66 fn prepare_fetch(
67 &mut self,
68 _version: gix_transport::Protocol,
69 _server: &Capabilities,
70 _features: &mut Vec<(&str, Option<Cow<'_, str>>)>,
71 _refs: &[Ref],
72 ) -> std::io::Result<Action> {
73 Ok(Action::Continue)
74 }
75
76 /// A method called repeatedly to negotiate the objects to receive in [`receive_pack(…)`][Delegate::receive_pack()].
77 ///
78 /// The first call has `previous_response` set to `None` as there was no previous response. Every call that follows `previous_response`
79 /// will be set to `Some`.
80 ///
81 /// ### If `previous_response` is `None`…
82 ///
83 /// Given a list of `arguments` to populate with wants, want-refs, shallows, filters and other contextual information to be
84 /// sent to the server. This method is called once.
85 /// Send the objects you `have` have afterwards based on the tips of your refs, in preparation to walk down their parents
86 /// with each call to `negotiate` to find the common base(s).
87 ///
88 /// Note that you should not `want` and object that you already have.
49aad941 89 /// `refs` are the tips of on the server side, effectively the latest objects _they_ have.
0a29b90c
FG
90 ///
91 /// Return `Action::Close` if you know that there are no `haves` on your end to allow the server to send all of its objects
92 /// as is the case during initial clones.
93 ///
94 /// ### If `previous_response` is `Some`…
95 ///
96 /// Populate `arguments` with the objects you `have` starting from the tips of _your_ refs, taking into consideration
97 /// the `previous_response` response of the server to see which objects they acknowledged to have. You have to maintain
98 /// enough state to be able to walk down from your tips on each call, if they are not in common, and keep setting `have`
99 /// for those which are in common if that helps teaching the server about our state and to acknowledge their existence on _their_ end.
100 /// This method is called until the other side signals they are ready to send a pack.
101 /// Return `Action::Close` if you want to give up before finding a common base. This can happen if the remote repository
102 /// has radically changed so there are no bases, or they are very far in the past, causing all objects to be sent.
103 fn negotiate(
104 &mut self,
105 refs: &[Ref],
106 arguments: &mut Arguments,
107 previous_response: Option<&Response>,
108 ) -> io::Result<Action>;
109}
110
111impl<T: DelegateBlocking> DelegateBlocking for Box<T> {
112 fn handshake_extra_parameters(&self) -> Vec<(String, Option<String>)> {
113 self.deref().handshake_extra_parameters()
114 }
115
116 fn prepare_ls_refs(
117 &mut self,
118 _server: &Capabilities,
119 _arguments: &mut Vec<BString>,
120 _features: &mut Vec<(&str, Option<Cow<'_, str>>)>,
121 ) -> io::Result<ls_refs::Action> {
122 self.deref_mut().prepare_ls_refs(_server, _arguments, _features)
123 }
124
125 fn prepare_fetch(
126 &mut self,
127 _version: gix_transport::Protocol,
128 _server: &Capabilities,
129 _features: &mut Vec<(&str, Option<Cow<'_, str>>)>,
130 _refs: &[Ref],
131 ) -> io::Result<Action> {
132 self.deref_mut().prepare_fetch(_version, _server, _features, _refs)
133 }
134
135 fn negotiate(
136 &mut self,
137 refs: &[Ref],
138 arguments: &mut Arguments,
139 previous_response: Option<&Response>,
140 ) -> io::Result<Action> {
141 self.deref_mut().negotiate(refs, arguments, previous_response)
142 }
143}
144
145impl<T: DelegateBlocking> DelegateBlocking for &mut T {
146 fn handshake_extra_parameters(&self) -> Vec<(String, Option<String>)> {
147 self.deref().handshake_extra_parameters()
148 }
149
150 fn prepare_ls_refs(
151 &mut self,
152 _server: &Capabilities,
153 _arguments: &mut Vec<BString>,
154 _features: &mut Vec<(&str, Option<Cow<'_, str>>)>,
155 ) -> io::Result<ls_refs::Action> {
156 self.deref_mut().prepare_ls_refs(_server, _arguments, _features)
157 }
158
159 fn prepare_fetch(
160 &mut self,
161 _version: gix_transport::Protocol,
162 _server: &Capabilities,
163 _features: &mut Vec<(&str, Option<Cow<'_, str>>)>,
164 _refs: &[Ref],
165 ) -> io::Result<Action> {
166 self.deref_mut().prepare_fetch(_version, _server, _features, _refs)
167 }
168
169 fn negotiate(
170 &mut self,
171 refs: &[Ref],
172 arguments: &mut Arguments,
173 previous_response: Option<&Response>,
174 ) -> io::Result<Action> {
175 self.deref_mut().negotiate(refs, arguments, previous_response)
176 }
177}
178
179#[cfg(feature = "blocking-client")]
180mod blocking_io {
181 use std::{
182 io::{self, BufRead},
183 ops::DerefMut,
184 };
185
186 use gix_features::progress::Progress;
187
188 use crate::{
189 fetch::{DelegateBlocking, Response},
190 handshake::Ref,
191 };
192
193 /// The protocol delegate is the bare minimal interface needed to fully control the [`fetch`][crate::fetch()] operation.
194 ///
195 /// Implementations of this trait are controlled by code with intricate knowledge about how fetching works in protocol version V1 and V2,
196 /// so you don't have to.
197 /// Everything is tucked away behind type-safety so 'nothing can go wrong'©. Runtime assertions assure invalid
198 /// features or arguments don't make it to the server in the first place.
199 /// Please note that this trait mostly corresponds to what V2 would look like, even though V1 is supported as well.
200 pub trait Delegate: DelegateBlocking {
201 /// Receive a pack provided from the given `input`.
202 ///
203 /// Use `progress` to emit your own progress messages when decoding the pack.
204 ///
205 /// `refs` of the remote side are provided for convenience, along with the parsed `previous_response` response in case you want
206 /// to check additional acks.
207 fn receive_pack(
208 &mut self,
209 input: impl io::BufRead,
210 progress: impl Progress,
211 refs: &[Ref],
212 previous_response: &Response,
213 ) -> io::Result<()>;
214 }
215
216 impl<T: Delegate> Delegate for Box<T> {
217 fn receive_pack(
218 &mut self,
219 input: impl BufRead,
220 progress: impl Progress,
221 refs: &[Ref],
222 previous_response: &Response,
223 ) -> io::Result<()> {
224 self.deref_mut().receive_pack(input, progress, refs, previous_response)
225 }
226 }
227
228 impl<T: Delegate> Delegate for &mut T {
229 fn receive_pack(
230 &mut self,
231 input: impl BufRead,
232 progress: impl Progress,
233 refs: &[Ref],
234 previous_response: &Response,
235 ) -> io::Result<()> {
236 self.deref_mut().receive_pack(input, progress, refs, previous_response)
237 }
238 }
239}
240#[cfg(feature = "blocking-client")]
241pub use blocking_io::Delegate;
242
243#[cfg(feature = "async-client")]
244mod async_io {
245 use std::{io, ops::DerefMut};
246
247 use async_trait::async_trait;
248 use futures_io::AsyncBufRead;
249 use gix_features::progress::Progress;
250
251 use crate::{
252 fetch::{DelegateBlocking, Response},
253 handshake::Ref,
254 };
255
256 /// The protocol delegate is the bare minimal interface needed to fully control the [`fetch`][crate::fetch()] operation.
257 ///
258 /// Implementations of this trait are controlled by code with intricate knowledge about how fetching works in protocol version V1 and V2,
259 /// so you don't have to.
260 /// Everything is tucked away behind type-safety so 'nothing can go wrong'©. Runtime assertions assure invalid
261 /// features or arguments don't make it to the server in the first place.
262 /// Please note that this trait mostly corresponds to what V2 would look like, even though V1 is supported as well.
263 #[async_trait(?Send)]
264 pub trait Delegate: DelegateBlocking {
265 /// Receive a pack provided from the given `input`, and the caller should consider it to be blocking as
266 /// most operations on the received pack are implemented in a blocking fashion.
267 ///
268 /// Use `progress` to emit your own progress messages when decoding the pack.
269 ///
270 /// `refs` of the remote side are provided for convenience, along with the parsed `previous_response` response in case you want
271 /// to check additional acks.
272 async fn receive_pack(
273 &mut self,
274 input: impl AsyncBufRead + Unpin + 'async_trait,
275 progress: impl Progress,
276 refs: &[Ref],
277 previous_response: &Response,
278 ) -> io::Result<()>;
279 }
280 #[async_trait(?Send)]
281 impl<T: Delegate> Delegate for Box<T> {
282 async fn receive_pack(
283 &mut self,
284 input: impl AsyncBufRead + Unpin + 'async_trait,
285 progress: impl Progress,
286 refs: &[Ref],
287 previous_response: &Response,
288 ) -> io::Result<()> {
289 self.deref_mut()
290 .receive_pack(input, progress, refs, previous_response)
291 .await
292 }
293 }
294
295 #[async_trait(?Send)]
296 impl<T: Delegate> Delegate for &mut T {
297 async fn receive_pack(
298 &mut self,
299 input: impl AsyncBufRead + Unpin + 'async_trait,
300 progress: impl Progress,
301 refs: &[Ref],
302 previous_response: &Response,
303 ) -> io::Result<()> {
304 self.deref_mut()
305 .receive_pack(input, progress, refs, previous_response)
306 .await
307 }
308 }
309}
310#[cfg(feature = "async-client")]
311pub use async_io::Delegate;
312
313use crate::ls_refs;