1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use std::str::FromStr;

use super::{Ipv4, Ipv6, StakeCredential};
use cml_core::DeserializeError;
use cml_crypto::RawBytesEncoding;

impl StakeCredential {
    // we don't implement RawBytesEncoding as from_raw_bytes() would be unable to distinguish
    pub fn to_raw_bytes(&self) -> &[u8] {
        match self {
            Self::PubKey { hash, .. } => hash.to_raw_bytes(),
            Self::Script { hash, .. } => hash.to_raw_bytes(),
        }
    }
}

#[derive(Debug, thiserror::Error)]
pub enum IPStringParsingError {
    #[error("Invalid IP Address String, expected period-separated bytes e.g. 0.0.0.0")]
    StringFormat,
    #[error("Deserializing from bytes: {0:?}")]
    DeserializeError(DeserializeError),
}

impl std::fmt::Display for Ipv4 {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            self.inner
                .iter()
                .map(ToString::to_string)
                .collect::<Vec<String>>()
                .join(".")
        )
    }
}

impl FromStr for Ipv4 {
    type Err = IPStringParsingError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        s.split('.')
            .map(FromStr::from_str)
            .collect::<Result<Vec<u8>, _>>()
            .map_err(|_e| IPStringParsingError::StringFormat)
            .and_then(|bytes| Self::new(bytes).map_err(IPStringParsingError::DeserializeError))
    }
}

impl serde::Serialize for Ipv4 {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_str(&self.to_string())
    }
}

impl<'de> serde::de::Deserialize<'de> for Ipv4 {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        let s = <String as serde::de::Deserialize>::deserialize(deserializer)?;
        Self::from_str(&s).map_err(|_e| {
            serde::de::Error::invalid_value(serde::de::Unexpected::Str(&s), &"invalid ipv4 address")
        })
    }
}

impl schemars::JsonSchema for Ipv4 {
    fn schema_name() -> String {
        String::from("Ipv4")
    }

    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
        String::json_schema(gen)
    }

    fn is_referenceable() -> bool {
        String::is_referenceable()
    }
}

impl std::fmt::Display for Ipv6 {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            self.inner
                .iter()
                .map(ToString::to_string)
                .collect::<Vec<String>>()
                .join(".")
        )
    }
}

impl FromStr for Ipv6 {
    type Err = IPStringParsingError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        s.split('.')
            .map(FromStr::from_str)
            .collect::<Result<Vec<u8>, _>>()
            .map_err(|_e| IPStringParsingError::StringFormat)
            .and_then(|bytes| Self::new(bytes).map_err(IPStringParsingError::DeserializeError))
    }
}

impl serde::Serialize for Ipv6 {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_str(&self.to_string())
    }
}

impl<'de> serde::de::Deserialize<'de> for Ipv6 {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        let s = <String as serde::de::Deserialize>::deserialize(deserializer)?;
        Self::from_str(&s).map_err(|_e| {
            serde::de::Error::invalid_value(serde::de::Unexpected::Str(&s), &"invalid ipv6 address")
        })
    }
}

impl schemars::JsonSchema for Ipv6 {
    fn schema_name() -> String {
        String::from("Ipv6")
    }

    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
        String::json_schema(gen)
    }

    fn is_referenceable() -> bool {
        String::is_referenceable()
    }
}