breadx/display/
prefetch.rs1use x11rb_protocol::{
7 protocol::{
8 bigreq::EnableRequest,
9 xc_misc::{GetXIDRangeReply, GetXIDRangeRequest},
10 xproto::{GetInputFocusReply, GetInputFocusRequest, QueryExtensionRequest},
11 },
12 x11_utils::{ExtensionInformation, ReplyRequest},
13 SequenceNumber,
14};
15
16use super::{
17 raw_request::{from_reply_request, BufferedRequest},
18 Display, RawReply,
19};
20use crate::Result;
21
22cfg_async! {
23 use super::{AsyncStatus, CanBeAsyncDisplay};
24 use core::task::Context;
25}
26
27pub struct Prefetch<T: PrefetchTarget> {
30 state: PrefetchState<T>,
31}
32
33enum PrefetchState<T: PrefetchTarget> {
34 Formatting(Option<BufferedRequest>),
36 #[allow(dead_code)]
38 Sending(Option<BufferedRequest>, u64),
39 Waiting(SequenceNumber),
41 Complete(T::Target),
43}
44
45pub trait PrefetchTarget: ReplyRequest {
47 type Target;
49
50 fn map_reply(reply: Self::Reply) -> Self::Target;
52
53 fn on_x11_error() -> Self::Target;
55}
56
57impl<T: PrefetchTarget + Default> Default for Prefetch<T> {
58 fn default() -> Self {
59 Self::new(Default::default())
60 }
61}
62
63impl<T: PrefetchTarget> From<PrefetchState<T>> for Prefetch<T> {
64 fn from(state: PrefetchState<T>) -> Self {
65 Self { state }
66 }
67}
68
69impl<T: PrefetchTarget> Prefetch<T> {
70 pub fn new(req: T) -> Self {
71 #[allow(clippy::redundant_closure_for_method_calls)]
72 let req = from_reply_request(req, |req| req.into());
73 PrefetchState::Formatting(Some(req)).into()
74 }
75
76 pub(crate) fn get_if_resolved(&self) -> Option<&T::Target> {
79 match self.state {
80 PrefetchState::Complete(ref c) => Some(c),
81 _ => None,
82 }
83 }
84
85 pub(crate) fn request_to_format(&mut self) -> &mut BufferedRequest {
89 match self.state {
90 PrefetchState::Formatting(Some(ref mut req)) => req,
91 _ => panic!("Prefetch is not formatting"),
92 }
93 }
94
95 pub(crate) fn sent_override(&mut self, seq: u64) {
97 match self.state {
98 PrefetchState::Sending(..) | PrefetchState::Formatting(..) => {
99 *self = PrefetchState::Waiting(seq).into();
100 }
101 _ => panic!("Prefetch is not sending or formatting"),
102 }
103 }
104
105 pub(crate) fn sequence(&self) -> u64 {
107 match self.state {
108 PrefetchState::Waiting(ref seq) => *seq,
109 _ => panic!("Prefetch is not waiting"),
110 }
111 }
112
113 pub(crate) fn read_reply(&mut self, reply: RawReply) -> Result<()> {
115 let reply: T::Reply = reply.into_reply()?;
116 let mapped = T::map_reply(reply);
117 *self = PrefetchState::Complete(mapped).into();
118 Ok(())
119 }
120
121 pub(crate) fn on_x11_error(&mut self) {
123 *self = PrefetchState::Complete(T::on_x11_error()).into();
124 }
125
126 pub fn evaluate(&mut self, display: &mut impl Display) -> Result<&T::Target> {
128 let request = self.request_to_format();
130 let seq = request.take(|request| display.send_request_raw(request))?;
131 self.sent_override(seq);
132 match display.wait_for_reply_raw(self.sequence()) {
133 Ok(reply) => {
134 self.read_reply(reply)?;
135 }
136 Err(e) if e.is_protocol_error() => {
137 self.on_x11_error();
138 }
139 Err(e) => return Err(e),
140 };
141 Ok(self.get_if_resolved().unwrap())
142 }
143}
144
145cfg_async! {
146 impl<T: PrefetchTarget> Prefetch<T> {
147 fn not_yet_formatted(&self) -> bool {
148 matches!(self.state, PrefetchState::Formatting(_))
149 }
150
151 fn not_yet_sent(&self) -> bool {
152 matches!(self.state, PrefetchState::Formatting(_) | PrefetchState::Sending(..))
153 }
154
155 fn not_yet_read(&self) -> bool {
156 !matches!(self.state, PrefetchState::Complete(_))
157 }
158
159 pub(crate) fn sent(&mut self) {
161 match self.state {
162 PrefetchState::Sending(_, seq) => *self = PrefetchState::Waiting(seq).into(),
163 _ => panic!("Prefetch is not sending"),
164 }
165 }
166
167 pub(crate) fn formatted(&mut self, seq: u64) {
169 match self.state {
170 PrefetchState::Formatting(ref mut request) => {
171 *self = PrefetchState::Sending(request.take(), seq).into();
172 }
173 _ => panic!("Prefetch is not formatting"),
174 }
175 }
176
177 pub(crate) fn request_to_send(&mut self) -> &mut BufferedRequest {
179 match self.state {
180 PrefetchState::Sending(Some(ref mut req), ..)
181 | PrefetchState::Formatting(Some(ref mut req)) => req,
182 _ => panic!("Prefetch is not sending"),
183 }
184 }
185
186 pub fn try_evaluate(
188 &mut self,
189 display: &mut impl CanBeAsyncDisplay,
190 ctx: &mut Context<'_>,
191 ) -> Result<AsyncStatus<&T::Target>> {
192 let span = tracing::trace_span!(
193 "try_evaluate",
194 formatted = !self.not_yet_formatted(),
195 sent = !self.not_yet_sent(),
196 read = !self.not_yet_read()
197 );
198 let _enter = span.enter();
199
200 if self.not_yet_formatted() {
202 tracing::trace!("formatting request");
203 let request = self.request_to_format();
204 let seq = mtry! {
205 request.borrow(|request| {
206 display.format_request(request, ctx)
207 })
208 };
209 self.formatted(seq);
210 }
211
212 if self.not_yet_sent() {
213 tracing::trace!("sending request");
214 let request = self.request_to_send();
215 mtry! {
216 request.borrow(|request| {
217 display.try_send_request_raw(request, ctx)
218 })
219 };
220 self.sent();
221 }
222
223 if self.not_yet_read() {
224 tracing::trace!("receiving reply");
225 match display.try_wait_for_reply_raw(self.sequence(), ctx) {
226 Ok(AsyncStatus::Ready(t)) => self.read_reply(t)?,
227 Ok(status) => return Ok(status.map(|_| unreachable!())),
228 Err(e) if e.is_protocol_error() => {
229 self.on_x11_error();
230 }
231 Err(e) => return Err(e),
232 }
233 }
234
235 Ok(AsyncStatus::Ready(self.get_if_resolved().unwrap()))
236 }
237 }
238}
239
240impl PrefetchTarget for EnableRequest {
243 type Target = Option<usize>;
244
245 fn map_reply(reply: Self::Reply) -> Self::Target {
246 let maxlen = reply.maximum_request_length as usize;
247 Some(maxlen)
248 }
249
250 fn on_x11_error() -> Self::Target {
251 None
252 }
253}
254
255impl<'a> PrefetchTarget for QueryExtensionRequest<'a> {
256 type Target = Option<ExtensionInformation>;
257
258 fn map_reply(reply: Self::Reply) -> Self::Target {
259 if !reply.present {
260 return None;
261 }
262
263 let info = ExtensionInformation {
264 major_opcode: reply.major_opcode,
265 first_error: reply.first_error,
266 first_event: reply.first_event,
267 };
268
269 Some(info)
270 }
271
272 fn on_x11_error() -> Self::Target {
273 None
274 }
275}
276
277impl PrefetchTarget for GetInputFocusRequest {
278 type Target = GetInputFocusReply;
279
280 fn map_reply(reply: Self::Reply) -> Self::Target {
281 reply
282 }
283
284 fn on_x11_error() -> Self::Target {
285 tracing::error!("synchronization should never error out");
286 GetInputFocusReply::default()
287 }
288}
289
290impl PrefetchTarget for GetXIDRangeRequest {
291 type Target = GetXIDRangeReply;
292
293 fn map_reply(reply: Self::Reply) -> Self::Target {
294 reply
295 }
296
297 fn on_x11_error() -> Self::Target {
298 tracing::error!("XID refresh should never error out");
299 GetXIDRangeReply::default()
300 }
301}