use std::{fmt::Display, net::UdpSocket, num::ParseIntError, str::FromStr}; use thiserror::Error; #[derive(Clone, Debug)] pub struct MacAddress([u8; 6]); #[derive(Error, Debug)] pub enum MacAddressParseError { #[error("Integer error: {}", .0)] ParseInt(#[from] ParseIntError), #[error("Mac address to short")] TooShort, } impl MacAddress { pub fn packet(&self) -> [u8; 102] { let mut magic = [0xffu8; 17 * 6]; let mut head: *mut u8 = &mut magic[0]; let mac: *const u8 = &self.0[0]; unsafe { for _ in 0..16 { head = head.offset(6); head.copy_from_nonoverlapping(mac, 6); } }; magic } pub async fn wake(&self) -> Result<(), std::io::Error> { let packet = self.packet(); let socket = UdpSocket::bind("0.0.0.0:0")?; socket.set_broadcast(true)?; socket.send_to(&packet, "255.255.255.255:9")?; Ok(()) } } impl Display for MacAddress { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{:0<2X}:{:0<2X}:{:0<2X}:{:0<2X}:{:0<2X}:{:0<2X}", self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5] ) } } impl From for [u8; 6] { fn from(value: MacAddress) -> Self { value.0 } } impl FromStr for MacAddress { type Err = MacAddressParseError; fn from_str(s: &str) -> Result { let address = s.split(":"); let address = address .map(|x| u8::from_str_radix(x, 16)) .collect::, ParseIntError>>()?; if address.len() != 6 { return Err(MacAddressParseError::TooShort); } Ok(MacAddress([ address[0], address[1], address[2], address[3], address[4], address[5], ])) } }