1use crate::error::GlobalError;
2use wayland_client::Proxy;
3
4/// A trait implemented by types that provide access to capability globals.
5///
6/// The returned global must be fully compatible with the provided `API_COMPAT_VERSION` generic
7/// argument. For example:
8///
9/// - A global that binds to `wl_compositor` with maximum version 4 could implement
10/// `ProvidesBoundGlobal<WlCompositor, 4>`, `ProvidesBoundGlobal<WlCompositor, 3>`,
11/// `ProvidesBoundGlobal<WlCompositor, 2>`, and `ProvidesBoundGlobal<WlCompositor, 1>` because
12/// versions 2-4 only add additional requests to the `wl_surface` API.
13/// - A global that binds to `wl_compositor` with maximum version 5 may only implement
14/// `ProvidesBoundGlobal<WlCompositor, 5>` because version 5 makes using `wl_surface::attach` with
15/// a nonzero offset a protocol error. A caller who is only aware of the version 4 API risks
16/// causing these protocol errors if it uses surfaces created by such a global.
17///
18/// Changes that cause compatibility breaks include:
19///
20/// - Adding a new event to the global or to any object created by the global.
21/// - Adding a new requirement to an existing request.
22///
23/// The resulting global may have a version lower than `API_COMPAT_VERSION` if, at runtime, the
24/// compositor does not support the new version. Clients should either be prepared to handle
25/// earlier versions of the protocol or use [`ProvidesBoundGlobal::with_min_version`] to produce an
26/// error in this case.
27///
28/// It is permitted to implement `ProvidesBoundGlobal` for versions that are higher than the
29/// maximum version you bind. When rustc gains the ability to constrain const parameters with
30/// integer bounds (`where API_COMPAT_VERSION >= 5`), implementations of this trait should be
31/// provided by specifying a lower bound for the compat version in order to avoid requiring version
32/// updates be done in lock-step.
33pub trait ProvidesBoundGlobal<I: Proxy, const API_COMPAT_VERSION: u32> {
34 fn bound_global(&self) -> Result<I, GlobalError>;
35 fn with_min_version(&self, version: u32) -> Result<I, GlobalError> {
36 let proxy: I = self.bound_global()?;
37 if proxy.version() < version {
38 Err(GlobalError::InvalidVersion {
39 name: I::interface().name,
40 required: version,
41 available: proxy.version(),
42 })
43 } else {
44 Ok(proxy)
45 }
46 }
47}
48
49/// A struct used as the UserData field for globals bound by SCTK.
50///
51/// This is used instead of `()` to allow multiple `Dispatch` impls on the same object.
52#[derive(Debug)]
53pub struct GlobalData;
54