1use std::collections::HashMap;
2
3use serde::{de::Visitor, Deserialize, Serialize};
4
5use crate::{
6 models::{instances::PropertiesObject, views::ViewReference},
7 IntegerStringOrObject,
8};
9
10#[derive(Debug, Clone, Copy, Serialize)]
13#[serde(transparent)]
14pub struct MaybeStringU64(pub u64);
15
16impl MaybeStringU64 {
17 pub fn new(v: u64) -> Self {
19 Self(v)
20 }
21}
22
23impl<'de> Deserialize<'de> for MaybeStringU64 {
24 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
25 where
26 D: serde::Deserializer<'de>,
27 {
28 struct MaybeStringVisitor;
29
30 impl Visitor<'_> for MaybeStringVisitor {
31 type Value = MaybeStringU64;
32
33 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
34 formatter.write_str("string or integer")
35 }
36
37 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
38 where
39 E: serde::de::Error,
40 {
41 Ok(MaybeStringU64::new(v))
42 }
43
44 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
45 where
46 E: serde::de::Error,
47 {
48 Ok(MaybeStringU64::new(
49 v.parse()
50 .map_err(|_| E::custom("failed to parse integer"))?,
51 ))
52 }
53 }
54
55 deserializer.deserialize_any(MaybeStringVisitor)
56 }
57}
58
59pub trait FromErrorDetail: Sized {
61 fn from_detail(detail: &HashMap<String, Box<IntegerStringOrObject>>) -> Option<Self>;
63}
64
65pub fn get_instance_properties<'a, TProperties>(
72 view: &ViewReference,
73 properties: &'a mut PropertiesObject<TProperties>,
74) -> Option<&'a TProperties> {
75 let space = view.space.to_owned();
76 let key = format!("{}/{}", view.external_id, view.version);
77
78 properties.get_mut(&space).and_then(|v| v.get(&key))
79}