use alloc::string::ToString;
pub use core::net::Ipv4Addr;
use core::{
fmt,
net::AddrParseError,
ops::Deref,
str::{self, FromStr},
};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::{
error::*,
rr::{RData, RecordData, RecordType},
serialize::{binary::*, txt::ParseError},
};
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct A(pub Ipv4Addr);
impl A {
pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
Self(Ipv4Addr::new(a, b, c, d))
}
pub(crate) fn from_tokens<'i, I: Iterator<Item = &'i str>>(
mut tokens: I,
) -> Result<Self, ParseError> {
let address: Ipv4Addr = tokens
.next()
.ok_or_else(|| ParseError::MissingToken("ipv4 address".to_string()))
.and_then(|s| Ipv4Addr::from_str(s).map_err(Into::into))?;
Ok(address.into())
}
}
impl RecordData for A {
fn try_borrow(data: &RData) -> Option<&Self> {
match data {
RData::A(ipv4) => Some(ipv4),
_ => None,
}
}
fn record_type(&self) -> RecordType {
RecordType::A
}
fn into_rdata(self) -> RData {
RData::A(self)
}
}
impl BinEncodable for A {
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
let segments = self.octets();
encoder.emit(segments[0])?;
encoder.emit(segments[1])?;
encoder.emit(segments[2])?;
encoder.emit(segments[3])?;
Ok(())
}
}
impl<'r> BinDecodable<'r> for A {
fn read(decoder: &mut BinDecoder<'r>) -> Result<Self, DecodeError> {
Ok(Ipv4Addr::new(
decoder.pop()?.unverified(),
decoder.pop()?.unverified(),
decoder.pop()?.unverified(),
decoder.pop()?.unverified(),
)
.into())
}
}
impl From<Ipv4Addr> for A {
fn from(a: Ipv4Addr) -> Self {
Self(a)
}
}
impl From<A> for Ipv4Addr {
fn from(a: A) -> Self {
a.0
}
}
impl Deref for A {
type Target = Ipv4Addr;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl fmt::Display for A {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", self.0)
}
}
impl FromStr for A {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, AddrParseError> {
Ipv4Addr::from_str(s).map(From::from)
}
}
#[cfg(test)]
mod mytests {
use alloc::vec::Vec;
use super::*;
use crate::serialize::binary::bin_tests::{test_emit_data_set, test_read_data_set};
fn get_data() -> Vec<(A, Vec<u8>)> {
vec![
(A::from(Ipv4Addr::UNSPECIFIED), vec![0, 0, 0, 0]), (A::from(Ipv4Addr::new(1, 0, 0, 0)), vec![1, 0, 0, 0]),
(A::from(Ipv4Addr::new(0, 1, 0, 0)), vec![0, 1, 0, 0]),
(A::from(Ipv4Addr::new(0, 0, 1, 0)), vec![0, 0, 1, 0]),
(A::from(Ipv4Addr::new(0, 0, 0, 1)), vec![0, 0, 0, 1]),
(A::from(Ipv4Addr::LOCALHOST), vec![127, 0, 0, 1]),
(
A::from(Ipv4Addr::new(192, 168, 64, 32)),
vec![192, 168, 64, 32],
),
]
}
#[test]
fn test_parse() {
test_read_data_set(get_data(), |mut d| A::read(&mut d));
}
#[test]
fn test_write_to() {
test_emit_data_set(get_data(), |e, d| d.emit(e));
}
}