For Add and Sub operations: what about if the result wasn’t another IP address but a u32 or u128? And do you have any thoughts on how such things should be handled instead of having these operations?
For example, if I am a DHCP server and want to determine the number of IP addresses in a user configured range. Or if I’m scanning IP addresses (for whatever reason) how would the next IP address be determined in a user defined range? Without allowing operations we are forced to convert to integer, operate on integer, and convert the integer back to IpAddr. Maybe the better option is to implement Range ops somehow for IpAddr in the stdlib?
The idea of some kind of IpMask type is interesting. Certainly you’re right, representing a mask using an IpAddr type does have problems, e.g. what’s the meaning of having is_loopback(), etc., on a mask?
What do you think about BitAnd and BitOr operations? For example, how should we determine the subnet or broadcast address? Either we convert to integer, mask, convert back to IpAddr. Or we allow these operations on IpAddr for some kind of other type (u32, u128, IpMask…).
With an IpMask type would you expect something like this?
let ip = Ipv4Addr::new(10, 1, 2, 3);
let mask = Ipv4Mask::new(24);
let subnet_addr = ip & mask; // <-- still need impl BitAnd<Ipv4Mask> for Ipv4Addr here
Or alternatively we implement something like a network(prefix: u8) and broadcast(prefix: u8) on IpAddrs:
let subnet_addr = ip.network(24);
let broadcast_addr = ip.broadcast(24);