Fetch User Keys - simple tool for fetching SSH keys from various sources
at master 2.6 kB view raw
1// SPDX-FileCopyrightText: 2025 Łukasz Niemier <#@hauleth.dev> 2// 3// SPDX-License-Identifier: EUPL-1.2 4 5use std::fmt; 6use std::str::FromStr; 7 8use serde::{Deserialize, Deserializer, de}; 9 10pub fn string_or_struct<'de, T, D>(deserializer: D) -> Result<T, D::Error> 11where 12 T: Deserialize<'de> + FromStr, 13 D: Deserializer<'de>, 14 <T as FromStr>::Err: fmt::Display, 15{ 16 // This is a Visitor that forwards string types to T's `FromStr` impl and 17 // forwards map types to T's `Deserialize` impl. The `PhantomData` is to 18 // keep the compiler from complaining about T being an unused generic type 19 // parameter. We need T in order to know the Value type for the Visitor 20 // impl. 21 struct StringOrStruct<T>(std::marker::PhantomData<fn() -> T>); 22 23 impl<'de, T> de::Visitor<'de> for StringOrStruct<T> 24 where 25 T: Deserialize<'de> + FromStr, 26 <T as FromStr>::Err: fmt::Display, 27 { 28 type Value = T; 29 30 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 31 formatter.write_str("string or map") 32 } 33 34 fn visit_str<E>(self, value: &str) -> Result<T, E> 35 where 36 E: de::Error, 37 { 38 FromStr::from_str(value).map_err(de::Error::custom) 39 } 40 41 fn visit_map<M>(self, map: M) -> Result<T, M::Error> 42 where 43 M: de::MapAccess<'de>, 44 { 45 // `MapAccessDeserializer` is a wrapper that turns a `MapAccess` 46 // into a `Deserializer`, allowing it to be used as the input to T's 47 // `Deserialize` implementation. T then deserializes itself using 48 // the entries from the map visitor. 49 Deserialize::deserialize(de::value::MapAccessDeserializer::new(map)) 50 } 51 } 52 53 deserializer.deserialize_any(StringOrStruct(Default::default())) 54} 55 56pub fn from_str<'de, T, D>(deserializer: D) -> Result<T, D::Error> 57where 58 T: FromStr, 59 D: Deserializer<'de>, 60 <T as FromStr>::Err: fmt::Display, 61{ 62 struct DeFromStr<T>(std::marker::PhantomData<T>); 63 64 impl<T> de::Visitor<'_> for DeFromStr<T> 65 where 66 T: FromStr, 67 <T as FromStr>::Err: fmt::Display, 68 { 69 type Value = T; 70 71 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 72 formatter.write_str("string or map") 73 } 74 75 fn visit_str<E>(self, value: &str) -> Result<T, E> 76 where 77 E: de::Error, 78 { 79 FromStr::from_str(value).map_err(de::Error::custom) 80 } 81 } 82 83 deserializer.deserialize_any(DeFromStr(Default::default())) 84}