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}