vrl/stdlib/
ip_aton.rs

1use crate::compiler::prelude::*;
2use std::net::Ipv4Addr;
3
4fn ip_aton(value: &Value) -> Resolved {
5    let ip: Ipv4Addr = value
6        .try_bytes_utf8_lossy()?
7        .parse()
8        .map_err(|err| format!("unable to parse IPv4 address: {err}"))?;
9    Ok(u32::from(ip).into())
10}
11
12#[derive(Clone, Copy, Debug)]
13pub struct IpAton;
14
15impl Function for IpAton {
16    fn identifier(&self) -> &'static str {
17        "ip_aton"
18    }
19
20    fn usage(&self) -> &'static str {
21        indoc! {"
22            Converts IPv4 address in numbers-and-dots notation into network-order
23            bytes represented as an integer.
24
25            This behavior mimics [inet_aton](https://linux.die.net/man/3/inet_aton).
26        "}
27    }
28
29    fn category(&self) -> &'static str {
30        Category::Ip.as_ref()
31    }
32
33    fn internal_failure_reasons(&self) -> &'static [&'static str] {
34        &["`value` is not a valid IPv4 address."]
35    }
36
37    fn return_kind(&self) -> u16 {
38        kind::INTEGER
39    }
40
41    fn parameters(&self) -> &'static [Parameter] {
42        const PARAMETERS: &[Parameter] = &[Parameter::required(
43            "value",
44            kind::BYTES,
45            "The IP address to convert to binary.",
46        )];
47        PARAMETERS
48    }
49
50    fn examples(&self) -> &'static [Example] {
51        &[example! {
52            title: "IPv4 to integer",
53            source: r#"ip_aton!("1.2.3.4")"#,
54            result: Ok("16909060"),
55        }]
56    }
57
58    fn compile(
59        &self,
60        _state: &state::TypeState,
61        _ctx: &mut FunctionCompileContext,
62        arguments: ArgumentList,
63    ) -> Compiled {
64        let value = arguments.required("value");
65
66        Ok(IpAtonFn { value }.as_expr())
67    }
68}
69
70#[derive(Debug, Clone)]
71struct IpAtonFn {
72    value: Box<dyn Expression>,
73}
74
75impl FunctionExpression for IpAtonFn {
76    fn resolve(&self, ctx: &mut Context) -> Resolved {
77        let value = self.value.resolve(ctx)?;
78        ip_aton(&value)
79    }
80
81    fn type_def(&self, _: &state::TypeState) -> TypeDef {
82        TypeDef::integer().fallible()
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use crate::value;
90
91    test_function![
92        ip_aton => IpAton;
93
94        invalid {
95            args: func_args![value: "i am not an ipaddress"],
96            want: Err("unable to parse IPv4 address: invalid IPv4 address syntax"),
97            tdef: TypeDef::integer().fallible(),
98        }
99
100        valid {
101            args: func_args![value: "1.2.3.4"],
102            want: Ok(value!(16_909_060)),
103            tdef: TypeDef::integer().fallible(),
104        }
105    ];
106}