k8_types/
metadata.rs

1use std::collections::HashMap;
2use std::fmt::{self, Display};
3use std::fmt::Debug;
4use std::marker::PhantomData;
5
6use serde::de::{DeserializeOwned, Deserializer};
7use serde::Deserialize;
8use serde::Serialize;
9
10use crate::Spec;
11
12pub const DEFAULT_NS: &str = "default";
13pub const TYPE_OPAQUE: &str = "Opaque";
14
15pub trait K8Meta {
16    /// resource name
17    fn name(&self) -> &str;
18
19    /// namespace
20    fn namespace(&self) -> &str;
21}
22
23pub trait LabelProvider: Sized {
24    fn set_label_map(self, labels: HashMap<String, String>) -> Self;
25
26    /// helper for setting list of labels
27    fn set_labels<T: ToString>(self, labels: Vec<(T, T)>) -> Self {
28        let mut label_map = HashMap::new();
29        for (key, value) in labels {
30            label_map.insert(key.to_string(), value.to_string());
31        }
32        self.set_label_map(label_map)
33    }
34}
35
36/// metadata associated with object when returned
37/// here name and namespace must be populated
38#[derive(Deserialize, Serialize, Eq, PartialEq, Debug, Default, Clone)]
39#[serde(rename_all = "camelCase", default)]
40pub struct ObjectMeta {
41    // mandatory fields
42    pub name: String,
43    #[serde(skip_serializing_if = "String::is_empty")]
44    pub namespace: String,
45    #[serde(skip_serializing_if = "String::is_empty")]
46    pub uid: String,
47    #[serde(skip_serializing_if = "String::is_empty")]
48    pub creation_timestamp: String,
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub generation: Option<i32>,
51    #[serde(skip_serializing_if = "String::is_empty")]
52    #[serde(default)]
53    pub resource_version: String,
54    // optional
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub cluster_name: Option<String>,
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub deletion_timestamp: Option<String>,
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub deletion_grace_period_seconds: Option<u32>,
61    #[serde(skip_serializing_if = "HashMap::is_empty")]
62    pub labels: HashMap<String, String>,
63    #[serde(skip_serializing_if = "Vec::is_empty")]
64    pub owner_references: Vec<OwnerReferences>,
65    #[serde(skip_serializing_if = "HashMap::is_empty")]
66    pub annotations: HashMap<String, String>,
67    #[serde(skip_serializing_if = "Vec::is_empty")]
68    pub finalizers: Vec<String>,
69}
70
71impl LabelProvider for ObjectMeta {
72    fn set_label_map(mut self, labels: HashMap<String, String>) -> Self {
73        self.labels = labels;
74        self
75    }
76}
77
78impl K8Meta for ObjectMeta {
79    fn name(&self) -> &str {
80        &self.name
81    }
82
83    fn namespace(&self) -> &str {
84        &self.namespace
85    }
86}
87
88impl ObjectMeta {
89    pub fn new<S>(name: S, name_space: S) -> Self
90    where
91        S: Into<String>,
92    {
93        Self {
94            name: name.into(),
95            namespace: name_space.into(),
96            ..Default::default()
97        }
98    }
99
100    /// provide builder pattern setter
101    pub fn set_labels<T: Into<String>>(mut self, labels: Vec<(T, T)>) -> Self {
102        let mut label_map = HashMap::new();
103        for (key, value) in labels {
104            label_map.insert(key.into(), value.into());
105        }
106        self.labels = label_map;
107        self
108    }
109
110    /// create with name and default namespace
111    pub fn named<S>(name: S) -> Self
112    where
113        S: Into<String>,
114    {
115        Self {
116            name: name.into(),
117            ..Default::default()
118        }
119    }
120
121    /// create owner references point to this metadata
122    /// if name or uid doesn't exists return none
123    pub fn make_owner_reference<S: Spec>(&self) -> OwnerReferences {
124        OwnerReferences {
125            api_version: S::api_version(),
126            kind: S::kind(),
127            name: self.name.clone(),
128            uid: self.uid.clone(),
129            // controller: Some(true),
130            ..Default::default()
131        }
132    }
133
134    pub fn namespace(&self) -> &str {
135        &self.namespace
136    }
137
138    /// create child references that points to this
139    pub fn make_child_input_metadata<S: Spec>(&self, childname: String) -> InputObjectMeta {
140        let owner_references: Vec<OwnerReferences> = vec![self.make_owner_reference::<S>()];
141
142        InputObjectMeta {
143            name: childname,
144            namespace: self.namespace().to_owned(),
145            owner_references,
146            ..Default::default()
147        }
148    }
149
150    pub fn as_input(&self) -> InputObjectMeta {
151        InputObjectMeta {
152            name: self.name.clone(),
153            namespace: self.namespace.clone(),
154            owner_references: self.owner_references.clone(),
155            ..Default::default()
156        }
157    }
158
159    pub fn as_item(&self) -> ItemMeta {
160        ItemMeta {
161            name: self.name.clone(),
162            namespace: self.namespace.clone(),
163        }
164    }
165
166    pub fn as_update(&self) -> UpdateItemMeta {
167        UpdateItemMeta {
168            name: self.name.clone(),
169            namespace: self.namespace.clone(),
170            resource_version: self.resource_version.clone(),
171            annotations: self.annotations.clone(),
172            owner_references: self.owner_references.clone(),
173            finalizers: self.finalizers.clone(),
174            labels: self.labels.clone(),
175        }
176    }
177}
178
179#[derive(Deserialize, Serialize, Debug, Default, Clone)]
180#[serde(rename_all = "camelCase")]
181pub struct InputObjectMeta {
182    pub name: String,
183    pub labels: HashMap<String, String>,
184    pub namespace: String,
185    pub owner_references: Vec<OwnerReferences>,
186    pub finalizers: Vec<String>,
187    pub annotations: HashMap<String, String>,
188}
189
190impl LabelProvider for InputObjectMeta {
191    fn set_label_map(mut self, labels: HashMap<String, String>) -> Self {
192        self.labels = labels;
193        self
194    }
195}
196
197impl fmt::Display for InputObjectMeta {
198    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
199        write!(f, "{}:{}", self.name, self.namespace)
200    }
201}
202
203impl K8Meta for InputObjectMeta {
204    fn name(&self) -> &str {
205        &self.name
206    }
207
208    fn namespace(&self) -> &str {
209        &self.namespace
210    }
211}
212
213impl InputObjectMeta {
214    // shorthand to create just with name and metadata
215    pub fn named<S: Into<String>>(name: S, namespace: S) -> Self {
216        InputObjectMeta {
217            name: name.into(),
218            namespace: namespace.into(),
219            ..Default::default()
220        }
221    }
222}
223
224impl From<ObjectMeta> for InputObjectMeta {
225    fn from(meta: ObjectMeta) -> Self {
226        Self {
227            name: meta.name,
228            namespace: meta.namespace,
229            ..Default::default()
230        }
231    }
232}
233
234/// used for retrieving,updating and deleting item
235#[derive(Deserialize, Serialize, Debug, Default, Clone)]
236#[serde(rename_all = "camelCase")]
237pub struct ItemMeta {
238    pub name: String,
239    pub namespace: String,
240}
241
242impl From<ObjectMeta> for ItemMeta {
243    fn from(meta: ObjectMeta) -> Self {
244        Self {
245            name: meta.name,
246            namespace: meta.namespace,
247        }
248    }
249}
250
251/// used for updating item
252#[derive(Deserialize, Serialize, Debug, Default, Clone)]
253#[serde(rename_all = "camelCase")]
254pub struct UpdateItemMeta {
255    pub name: String,
256    pub namespace: String,
257    pub labels: HashMap<String, String>,
258    pub resource_version: String,
259    pub annotations: HashMap<String, String>,
260    pub owner_references: Vec<OwnerReferences>,
261    pub finalizers: Vec<String>,
262}
263
264impl From<ObjectMeta> for UpdateItemMeta {
265    fn from(meta: ObjectMeta) -> Self {
266        Self {
267            name: meta.name,
268            labels: meta.labels,
269            namespace: meta.namespace,
270            resource_version: meta.resource_version,
271            annotations: meta.annotations,
272            owner_references: meta.owner_references,
273            finalizers: meta.finalizers,
274        }
275    }
276}
277
278impl K8Meta for UpdateItemMeta {
279    fn name(&self) -> &str {
280        &self.name
281    }
282
283    fn namespace(&self) -> &str {
284        &self.namespace
285    }
286}
287
288#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
289#[serde(rename_all = "camelCase")]
290pub struct OwnerReferences {
291    pub api_version: String,
292    #[serde(default)]
293    pub block_owner_deletion: bool,
294    pub controller: Option<bool>,
295    pub kind: String,
296    pub name: String,
297    pub uid: String,
298}
299
300impl Default for OwnerReferences {
301    fn default() -> Self {
302        Self {
303            api_version: "v1".to_owned(),
304            block_owner_deletion: false,
305            controller: None,
306            kind: "".to_owned(),
307            uid: "".to_owned(),
308            name: "".to_owned(),
309        }
310    }
311}
312
313#[derive(Debug, Clone)]
314pub enum DeleteStatus<S>
315where
316    S: Spec,
317{
318    Deleted(MetaStatus),
319    ForegroundDelete(K8Obj<S>),
320}
321
322#[derive(Deserialize, Debug, Clone)]
323#[serde(rename_all = "camelCase")]
324pub struct MetaStatus {
325    pub api_version: String,
326    pub code: Option<u16>,
327    pub details: Option<StatusDetails>,
328    pub kind: String,
329    pub message: Option<String>,
330    pub reason: Option<String>,
331    pub status: StatusEnum,
332}
333
334impl Display for MetaStatus {
335    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
336        write!(f, "{}", self.status)?;
337
338        if let Some(ref code) = self.code {
339            write!(f, " ({code})")?;
340        }
341        if let Some(ref message) = self.message {
342            write!(f, ":{message}.")?;
343        }
344
345        Ok(())
346    }
347}
348
349impl std::error::Error for MetaStatus {}
350
351/// Default status implementation
352#[allow(clippy::upper_case_acronyms)]
353#[derive(Deserialize, Debug, Eq, PartialEq, Clone)]
354pub enum StatusEnum {
355    #[serde(rename = "Success")]
356    SUCCESS,
357    #[serde(rename = "Failure")]
358    FAILURE,
359}
360
361impl Display for StatusEnum {
362    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
363        match self {
364            Self::SUCCESS => write!(f, "Success"),
365            Self::FAILURE => write!(f, "Failure"),
366        }
367    }
368}
369
370/*
371#[serde(deserialize_with = "StatusEnum::deserialize_with")]
372    pub status: StatusEnum,
373*/
374
375#[derive(Deserialize, Serialize, Debug, Clone)]
376pub struct StatusDetails {
377    pub name: String,
378    pub group: Option<String>,
379    pub kind: String,
380    pub uid: Option<String>,
381}
382
383#[derive(Deserialize, Serialize, Debug, Default, Clone)]
384#[serde(rename_all = "camelCase")]
385#[serde(bound(serialize = "S: Serialize"))]
386#[serde(bound(deserialize = "S: DeserializeOwned"))]
387pub struct K8Obj<S>
388where
389    S: Spec,
390{
391    #[serde(default = "S::api_version")]
392    pub api_version: String,
393    #[serde(default = "S::kind")]
394    pub kind: String,
395    #[serde(default)]
396    pub metadata: ObjectMeta,
397    #[serde(default)]
398    pub spec: S,
399    #[serde(flatten)]
400    pub header: S::Header,
401    #[serde(default)]
402    pub status: S::Status,
403}
404
405impl<S> K8Obj<S>
406where
407    S: Spec,
408{
409    #[allow(dead_code)]
410    pub fn new<N>(name: N, spec: S) -> Self
411    where
412        N: Into<String>,
413    {
414        Self {
415            api_version: S::api_version(),
416            kind: S::kind(),
417            metadata: ObjectMeta::named(name),
418            spec,
419            ..Default::default()
420        }
421    }
422
423    #[allow(dead_code)]
424    pub fn set_status(mut self, status: S::Status) -> Self {
425        self.status = status;
426        self
427    }
428
429    pub fn as_status_update(&self, status: S::Status) -> UpdateK8ObjStatus<S> {
430        UpdateK8ObjStatus {
431            api_version: S::api_version(),
432            kind: S::kind(),
433            metadata: self.metadata.as_update(),
434            status,
435            ..Default::default()
436        }
437    }
438}
439
440impl<S> K8Obj<S>
441where
442    S: Spec,
443{
444    pub fn as_input(&self) -> InputK8Obj<S> {
445        K8SpecObj {
446            api_version: self.api_version.clone(),
447            kind: self.kind.clone(),
448            metadata: self.metadata.as_input(),
449            spec: self.spec.clone(),
450            ..Default::default()
451        }
452    }
453
454    pub fn as_update(&self) -> K8SpecObj<S, UpdateItemMeta> {
455        K8SpecObj {
456            api_version: self.api_version.clone(),
457            kind: self.kind.clone(),
458            metadata: self.metadata.as_update(),
459            spec: self.spec.clone(),
460            ..Default::default()
461        } as K8SpecObj<S, UpdateItemMeta>
462    }
463}
464
465/// For creating, only need spec
466#[derive(Deserialize, Serialize, Debug, Default, Clone)]
467#[serde(rename_all = "camelCase")]
468#[serde(bound(serialize = "S: Serialize, M: Serialize"))]
469#[serde(bound(deserialize = "S: DeserializeOwned, M: DeserializeOwned"))]
470pub struct K8SpecObj<S, M>
471where
472    S: Spec,
473{
474    pub api_version: String,
475    pub kind: String,
476    pub metadata: M,
477    pub spec: S,
478    #[serde(flatten)]
479    pub header: S::Header,
480}
481
482impl<S, M> K8SpecObj<S, M>
483where
484    S: Spec,
485{
486    pub fn new(spec: S, metadata: M) -> Self
487    where
488        M: Default,
489    {
490        Self {
491            api_version: S::api_version(),
492            kind: S::kind(),
493            metadata,
494            spec,
495            ..Default::default()
496        }
497    }
498}
499
500pub type InputK8Obj<S> = K8SpecObj<S, InputObjectMeta>;
501#[deprecated(note = "use UpdatedK8Obj instead")]
502pub type UpdateK8Obj<S> = K8SpecObj<S, ItemMeta>;
503pub type UpdatedK8Obj<S> = K8SpecObj<S, UpdateItemMeta>;
504
505/// Used for updating k8obj
506#[derive(Deserialize, Serialize, Debug, Default, Clone)]
507#[serde(rename_all = "camelCase")]
508pub struct UpdateK8ObjStatus<S>
509where
510    S: Spec,
511{
512    pub api_version: String,
513    pub kind: String,
514    pub metadata: UpdateItemMeta,
515    pub status: S::Status,
516    pub data: PhantomData<S>,
517}
518
519impl<S> UpdateK8ObjStatus<S>
520where
521    S: Spec,
522{
523    pub fn new(status: S::Status, metadata: UpdateItemMeta) -> Self {
524        Self {
525            api_version: S::api_version(),
526            kind: S::kind(),
527            metadata,
528            status,
529            ..Default::default()
530        }
531    }
532}
533
534#[allow(deprecated)]
535impl<S> From<UpdateK8Obj<S>> for InputK8Obj<S>
536where
537    S: Spec,
538{
539    fn from(update: UpdateK8Obj<S>) -> Self {
540        Self {
541            api_version: update.api_version,
542            kind: update.kind,
543            metadata: update.metadata.into(),
544            spec: update.spec,
545            ..Default::default()
546        }
547    }
548}
549
550impl From<ItemMeta> for InputObjectMeta {
551    fn from(update: ItemMeta) -> Self {
552        Self {
553            name: update.name,
554            namespace: update.namespace,
555            ..Default::default()
556        }
557    }
558}
559
560/// name is optional for template
561#[derive(Deserialize, Serialize, Debug, Default, Clone, Eq, PartialEq)]
562#[serde(rename_all = "camelCase", default)]
563pub struct TemplateMeta {
564    pub name: Option<String>,
565    pub creation_timestamp: Option<String>,
566    pub labels: HashMap<String, String>,
567    pub annotations: HashMap<String, String>,
568}
569
570impl LabelProvider for TemplateMeta {
571    fn set_label_map(mut self, labels: HashMap<String, String>) -> Self {
572        self.labels = labels;
573        self
574    }
575}
576
577impl TemplateMeta {
578    /// create with name and default namespace
579    pub fn named<S>(name: S) -> Self
580    where
581        S: Into<String>,
582    {
583        Self {
584            name: Some(name.into()),
585            ..Default::default()
586        }
587    }
588}
589
590#[derive(Deserialize, Serialize, Debug, Default, Clone, Eq, PartialEq)]
591#[serde(rename_all = "camelCase")]
592pub struct TemplateSpec<S> {
593    pub metadata: Option<TemplateMeta>,
594    pub spec: S,
595}
596
597impl<S> TemplateSpec<S> {
598    pub fn new(spec: S) -> Self {
599        TemplateSpec {
600            metadata: None,
601            spec,
602        }
603    }
604}
605
606#[derive(Deserialize, Serialize, Debug, Clone)]
607#[serde(rename_all = "camelCase")]
608#[serde(bound(serialize = "K8Obj<S>: Serialize"))]
609#[serde(bound(deserialize = "K8Obj<S>: DeserializeOwned"))]
610pub struct K8List<S>
611where
612    S: Spec,
613{
614    pub api_version: String,
615    pub kind: String,
616    pub metadata: ListMetadata,
617    pub items: Vec<K8Obj<S>>,
618}
619
620impl<S> K8List<S>
621where
622    S: Spec,
623{
624    #[allow(dead_code)]
625    pub fn new() -> Self {
626        K8List {
627            api_version: S::api_version(),
628            items: vec![],
629            kind: S::kind(),
630            metadata: ListMetadata {
631                _continue: None,
632                resource_version: S::api_version(),
633            },
634        }
635    }
636}
637
638impl<S> Default for K8List<S>
639where
640    S: Spec,
641{
642    fn default() -> Self {
643        Self::new()
644    }
645}
646
647pub trait DeserializeWith: Sized {
648    fn deserialize_with<'de, D>(de: D) -> Result<Self, D::Error>
649    where
650        D: Deserializer<'de>;
651}
652
653#[allow(clippy::upper_case_acronyms)]
654#[derive(Serialize, Deserialize, Debug, Clone)]
655#[serde(tag = "type", content = "object")]
656#[serde(bound(serialize = "K8Obj<S>: Serialize"))]
657#[serde(bound(deserialize = "K8Obj<S>: DeserializeOwned"))]
658pub enum K8Watch<S>
659where
660    S: Spec,
661{
662    ADDED(K8Obj<S>),
663    MODIFIED(K8Obj<S>),
664    DELETED(K8Obj<S>),
665}
666
667#[derive(Deserialize, Serialize, Debug, Clone)]
668#[serde(rename_all = "camelCase")]
669pub struct ListMetadata {
670    pub _continue: Option<String>,
671    #[serde(default)]
672    pub resource_version: String,
673}
674
675#[derive(Deserialize, Serialize, Default, Debug, Eq, PartialEq, Clone)]
676#[serde(rename_all = "camelCase")]
677pub struct LabelSelector {
678    pub match_labels: HashMap<String, String>,
679}
680
681impl LabelSelector {
682    pub fn new_labels<T: Into<String>>(labels: Vec<(T, T)>) -> Self {
683        let mut match_labels = HashMap::new();
684        for (key, value) in labels {
685            match_labels.insert(key.into(), value.into());
686        }
687        LabelSelector { match_labels }
688    }
689}
690
691#[derive(Deserialize, Serialize, Default, Debug, Clone, Eq, PartialEq)]
692#[serde(rename_all = "camelCase")]
693pub struct Env {
694    pub name: String,
695    pub value: Option<String>,
696    pub value_from: Option<EnvVarSource>,
697}
698
699impl Env {
700    pub fn key_value<T: Into<String>>(name: T, value: T) -> Self {
701        Self {
702            name: name.into(),
703            value: Some(value.into()),
704            value_from: None,
705        }
706    }
707
708    pub fn key_field_ref<T: Into<String>>(name: T, field_path: T) -> Self {
709        Self {
710            name: name.into(),
711            value: None,
712            value_from: Some(EnvVarSource::FieldRef(ObjectFieldSelector {
713                field_path: field_path.into(),
714            })),
715        }
716    }
717}
718
719#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
720#[serde(rename_all = "camelCase")]
721pub enum EnvVarSource {
722    ConfigMapKeyRef(KeySelector),
723    FieldRef(ObjectFieldSelector),
724    ResourceFieldRef(ResourceFieldSelector),
725    SecretKeyRef(KeySelector),
726}
727
728#[derive(Deserialize, Serialize, Default, Debug, Clone, Eq, PartialEq)]
729#[serde(rename_all = "camelCase")]
730pub struct KeySelector {
731    pub key: String,
732    pub name: String,
733    #[serde(default)]
734    pub optional: bool,
735}
736
737#[derive(Deserialize, Serialize, Default, Debug, Clone, Eq, PartialEq)]
738#[serde(rename_all = "camelCase")]
739pub struct ObjectFieldSelector {
740    pub field_path: String,
741}
742
743#[derive(Deserialize, Serialize, Default, Debug, Clone, Eq, PartialEq)]
744#[serde(rename_all = "camelCase")]
745pub struct ResourceFieldSelector {
746    pub container_name: Option<String>,
747    pub divisor: Option<String>,
748    pub resource: String,
749}
750
751#[cfg(test)]
752mod test {
753
754    use super::Env;
755    use super::ObjectMeta;
756
757    #[test]
758    fn test_metadata_label() {
759        let metadata =
760            ObjectMeta::default().set_labels(vec![("app".to_owned(), "test".to_owned())]);
761
762        let maps = metadata.labels;
763        assert_eq!(maps.len(), 1);
764        assert_eq!(maps.get("app").unwrap(), "test");
765    }
766
767    #[test]
768    fn test_env() {
769        let env = Env::key_value("lang", "english");
770        assert_eq!(env.name, "lang");
771        assert_eq!(env.value, Some("english".to_owned()));
772    }
773}
774
775/*
776#[cfg(test)]
777mod test_delete {
778
779
780
781    use serde_json;
782    use serde::{ Serialize,Deserialize};
783
784    use crate::{ Spec,Status, DefaultHeader, Crd, CrdNames};
785    use super::DeleteResponse;
786
787    const TEST_API: Crd = Crd {
788        group: "test",
789        version: "v1",
790        names: CrdNames {
791            kind: "test",
792            plural: "test",
793            singular: "test",
794        },
795    };
796
797
798    #[derive(Deserialize, Serialize, Default, Debug, Clone)]
799    struct TestSpec {}
800
801    impl Spec for TestSpec {
802        type Status = TestStatus;
803        type Header = DefaultHeader;
804
805        fn metadata() -> &'static Crd {
806            &TEST_API
807        }
808    }
809
810    #[derive(Deserialize, Serialize,Debug, Default,Clone)]
811    struct TestStatus(bool);
812
813    impl Status for TestStatus{}
814
815    #[test]
816    fn test_deserialize_test_options() {
817        let data = r#"
818        {
819            "kind": "Status",
820            "apiVersion": "v1",
821            "metadata": {
822
823            },
824            "status": "Success",
825            "details": {
826              "name": "test",
827              "group": "test.infinyon.com",
828              "kind": "test",
829              "uid": "62fc6733-c505-40c1-9dbb-dcd71e93528f"
830            }"#;
831
832        // Parse the string of data into serde_json::Value.
833        let _status: DeleteResponse<TestSpec> = serde_json::from_str(data).expect("response");
834    }
835}
836*/
837
838/*
839
840
841impl<'de, S> Deserialize<'de> for DeleteResponse<S>
842    where
843        S: Spec
844{
845
846    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
847        where D: Deserializer<'de>,
848    {
849        use serde::de::{ Visitor, MapAccess};
850
851        struct StatusVisitor<S: Spec>(PhantomData<fn() -> S>);
852
853        impl<'de,S> Visitor<'de> for StatusVisitor<S>
854            where
855                S: Spec,
856                DeleteResponse<S>: Deserialize<'de>,
857        {
858            type Value = DeleteResponse<S>;
859
860            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
861                formatter.write_str("string or json")
862            }
863
864            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
865            where
866                E: de::Error,
867            {
868                match value {
869                    "Success" => Ok(DeleteResponse::OkStatus(StatusEnum::SUCCESS)),
870                    "Failure" => Ok(DeleteResponse::OkStatus(StatusEnum::FAILURE)),
871                    _ => Err(de::Error::custom(format!("unrecognized status: {}",value)))
872                }
873
874
875            }
876
877            fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
878            where
879                M: MapAccess<'de>,
880            {
881                Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))
882            }
883        }
884
885        deserializer.deserialize_any(StatusVisitor(PhantomData))
886    }
887
888}
889*/