nuts_tool_api/
info.rs

1// MIT License
2//
3// Copyright (c) 2024 Robin Doer
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to
7// deal in the Software without restriction, including without limitation the
8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9// sell copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21// IN THE SOFTWARE.
22
23#[cfg(test)]
24#[cfg(feature = "tool")]
25mod tests;
26
27use serde::{Deserialize, Deserializer, Serialize};
28
29/// Current revision of the exchange protocol between plugin and tool.
30///
31/// # History
32///
33/// ## Revision 0
34///
35/// Initial revision.
36///
37/// ## Revision 1
38///
39/// The `revision` field was added to [`PluginInfo`]. The
40/// [`crate::OkResponse::Map`] response of a [`crate::Request::PluginInfo`]
41/// request now contains a `revision` key. Therfore, without the `revision` key
42/// in the response you will have a revision `0`.
43pub const CURRENT_REVISION: u32 = 1;
44
45fn de_revision<'de, D: Deserializer<'de>>(deserializer: D) -> Result<u32, D::Error> {
46    let rev: u32 = Deserialize::deserialize(deserializer)?;
47
48    // Revision 0 has no revision field in PluginInfo. Therefore there cannot
49    // be a such a revision.
50
51    if rev > 0 {
52        Ok(rev)
53    } else {
54        Err(serde::de::Error::custom(
55            "revision 0 cannot be explicity specified",
56        ))
57    }
58}
59
60/// Information of a plugin
61#[derive(Debug, Deserialize, Serialize)]
62pub struct PluginInfo {
63    name: String,
64    version: String,
65    #[serde(default)]
66    #[serde(deserialize_with = "de_revision")]
67    revision: u32,
68}
69
70impl PluginInfo {
71    /// Creates a new `PluginInfo` instance.
72    pub fn new<N: AsRef<str>, V: AsRef<str>>(name: N, version: V) -> PluginInfo {
73        PluginInfo {
74            name: name.as_ref().to_string(),
75            version: version.as_ref().to_string(),
76            revision: CURRENT_REVISION,
77        }
78    }
79
80    /// Returns the name of the plugin.
81    pub fn name(&self) -> &str {
82        &self.name
83    }
84
85    /// Returns the version of the plugin.
86    pub fn version(&self) -> &str {
87        &self.version
88    }
89
90    /// Returns the protocol revision.
91    pub fn revision(&self) -> u32 {
92        self.revision
93    }
94}
95
96#[cfg(feature = "tool")]
97mod tool_impls {
98    use std::collections::HashMap;
99    use std::convert::TryFrom;
100
101    use crate::info::PluginInfo;
102    use crate::tool::PluginError::{self, InvalidResponse};
103
104    impl TryFrom<HashMap<String, String>> for PluginInfo {
105        type Error = PluginError;
106
107        fn try_from(mut map: HashMap<String, String>) -> Result<Self, PluginError> {
108            let name = map.remove("name").ok_or(InvalidResponse)?;
109            let version = map.remove("version").ok_or(InvalidResponse)?;
110
111            // In revision 0 the revision field is missing.
112            let revision = map
113                .remove("revision")
114                .map_or(Ok(Default::default()), |s| s.parse())
115                .map_err(|_| InvalidResponse)?;
116
117            Ok(PluginInfo {
118                name,
119                version,
120                revision,
121            })
122        }
123    }
124}