xrpicker/
manifest.rs

1// Copyright 2022, Collabora, Ltd.
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use std::path::Path;
5
6use serde::Deserialize;
7
8use crate::path_simplifier::PathSimplifier;
9
10// The string to put between two file names/paths to indicate that one points to another,
11// when used in a *multiline-capable* GUI field.
12pub(crate) const FILE_INDIRECTION_ARROW: &str = "\n    той ";
13
14pub(crate) trait GenericManifest {
15    /// Get the library path as stored in the manifest
16    fn library_path(&self) -> &str;
17
18    /// Check the file format version
19    fn is_file_format_version_ok(&self) -> bool;
20
21    /// Does the library path use the system shared library search path?
22    fn uses_search_path(&self) -> bool {
23        !self.library_path().contains('/') && !self.library_path().contains('\\')
24    }
25
26    /// Should the library be searched for relative to the manifest?
27    fn library_relative_to_manifest(&self) -> bool {
28        let path = self.library_path();
29        !self.uses_search_path()
30            && !path.starts_with('/')
31            && !path.starts_with('\\')
32            && path.chars().nth(1) != Some(':')
33    }
34
35    /// Describe this manifest by using the manifest path and library path
36    fn describe_manifest(&self, manifest_path: &Path) -> String {
37        let simplifier = PathSimplifier::new();
38        let manifest_path = simplifier.simplify(manifest_path);
39        let manifest = manifest_path.display();
40        if self.uses_search_path() {
41            format!(
42                "{}{}{} in the dynamic library search path",
43                manifest,
44                FILE_INDIRECTION_ARROW,
45                self.library_path()
46            )
47        } else if self.library_relative_to_manifest() {
48            format!(
49                "{}{}{} relative to the manifest",
50                manifest,
51                FILE_INDIRECTION_ARROW,
52                self.library_path()
53            )
54        } else {
55            let lib_path = Path::new(self.library_path());
56            format!(
57                "{}{}{}",
58                manifest,
59                FILE_INDIRECTION_ARROW,
60                simplifier.simplify(lib_path).display()
61            )
62        }
63    }
64}
65
66/// Non-top-level objects in a runtime manifest
67pub(crate) mod json_subobjects {
68    use serde::Deserialize;
69
70    /// The optional table of function symbol renaming in a runtime manifest
71    #[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
72    pub(crate) struct RuntimeFunctions {
73        #[serde(rename = "xrNegotiateLoaderRuntimeInterface")]
74        pub(crate) xr_negotiate_loader_runtime_interface: Option<String>,
75    }
76
77    /// The main object in a runtime manifest
78    #[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
79    pub(crate) struct Runtime {
80        pub(crate) library_path: String,
81        pub(crate) name: Option<String>,
82        pub(crate) functions: Option<RuntimeFunctions>,
83    }
84}
85
86/// Top level structure corresponding to a runtime manifest
87#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
88pub(crate) struct RuntimeManifest {
89    file_format_version: String,
90    pub(crate) runtime: json_subobjects::Runtime,
91}
92
93impl GenericManifest for RuntimeManifest {
94    fn library_path(&self) -> &str {
95        &self.runtime.library_path
96    }
97    fn is_file_format_version_ok(&self) -> bool {
98        self.file_format_version == "1.0.0"
99    }
100}