Структура AddrParseError

#![allow(unused)]
fn main() {
pub struct AddrParseError(_);
}

Ошибка, которая может быть возвращена при анализе адреса IP или сокета.

Эта ошибка используется как ошибка типа для FromStr реализаций различных типов адресов в этом модуле, таких как IpAddr, SocketAddr, Ipv4Addr и других.

Примеры

#![allow(unused)]
fn main() {
use std::net::IpAddr;
use std::str::FromStr;

let invalid_str = "not-an-ip-address";
let err = IpAddr::from_str(invalid_str).unwrap_err();

println!("Ошибка анализа: {}", err);
}

Методы

source

#![allow(unused)]
fn main() {
pub fn source(&self) -> Option<&(dyn Error + 'static)>
}

Возвращает исходную ошибку, если таковая имеется.

Этот метод предоставляет доступ к исходной ошибке, которая привела к созданию этой ошибки анализа.

Примеры

#![allow(unused)]
fn main() {
use std::net::IpAddr;
use std::str::FromStr;

let invalid_str = "256.256.256.256"; // Неверный IP-адрес
let err = IpAddr::from_str(invalid_str).unwrap_err();

if let Some(source) = err.source() {
    println!("Исходная ошибка: {}", source);
}
}

Трайт-реализации

Display

#![allow(unused)]
fn main() {
impl Display for AddrParseError
}

Реализует отображение для AddrParseError.

Примеры

#![allow(unused)]
fn main() {
use std::net::IpAddr;
use std::str::FromStr;

let invalid_str = "not-an-ip";
let err = IpAddr::from_str(invalid_str).unwrap_err();

println!("Ошибка: {}", err); // Выводит читаемое сообщение об ошибке
}

Debug

#![allow(unused)]
fn main() {
impl Debug for AddrParseError
}

Реализует отладочное отображение для AddrParseError.

Примеры

#![allow(unused)]
fn main() {
use std::net::IpAddr;
use std::str::FromStr;

let invalid_str = "300.400.500.600";
let err = IpAddr::from_str(invalid_str).unwrap_err();

println!("Отладочная информация: {:?}", err);
}

Error

#![allow(unused)]
fn main() {
impl Error for AddrParseError
}

Реализует трейт Error для AddrParseError.

Примеры

#![allow(unused)]
fn main() {
use std::net::IpAddr;
use std::str::FromStr;
use std::error::Error;

let invalid_str = "invalid-ip-address";
let err = IpAddr::from_str(invalid_str).unwrap_err();

// Использование методов из трейта Error
println!("Описание: {}", err);
if let Some(source) = err.source() {
    println!("Источник: {}", source);
}
}

Clone, Copy

#![allow(unused)]
fn main() {
impl Clone for AddrParseError
impl Copy for AddrParseError
}

Реализует клонирование и копирование для AddrParseError.

Примеры

#![allow(unused)]
fn main() {
use std::net::IpAddr;
use std::str::FromStr;

let invalid_str = "999.999.999.999";
let err = IpAddr::from_str(invalid_str).unwrap_err();
let err_clone = err.clone(); // Клонирование ошибки

println!("Оригинальная ошибка: {}", err);
println!("Клонированная ошибка: {}", err_clone);
}

Eq, PartialEq

#![allow(unused)]
fn main() {
impl Eq for AddrParseError
impl PartialEq for AddrParseError
}

Реализует сравнение для AddrParseError.

Примеры

#![allow(unused)]
fn main() {
use std::net::IpAddr;
use std::str::FromStr;

let err1 = IpAddr::from_str("invalid1").unwrap_err();
let err2 = IpAddr::from_str("invalid2").unwrap_err();

// Ошибки анализа считаются равными, независимо от входной строки
assert_eq!(err1, err2);
}

Примеры использования

Базовое использование с обработкой ошибок

use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;

fn parse_ip_address(ip_str: &str) -> Result<IpAddr, String> {
    IpAddr::from_str(ip_str)
        .map_err(|e| format!("Неверный IP-адрес '{}': {}", ip_str, e))
}

fn parse_socket_address(addr_str: &str) -> Result<SocketAddr, String> {
    SocketAddr::from_str(addr_str)
        .map_err(|e| format!("Неверный адрес сокета '{}': {}", addr_str, e))
}

fn main() {
    // Тестирование валидных адресов
    let valid_ips = ["127.0.0.1", "::1", "192.168.1.1"];
    for ip_str in &valid_ips {
        match parse_ip_address(ip_str) {
            Ok(ip) => println!("Успешно разобран IP: {}", ip),
            Err(e) => println!("Ошибка: {}", e),
        }
    }
    
    // Тестирование невалидных адресов
    let invalid_ips = ["256.256.256.256", "not_an_ip", "123.456.789.000"];
    for ip_str in &invalid_ips {
        match parse_ip_address(ip_str) {
            Ok(ip) => println!("Успешно разобран IP: {}", ip),
            Err(e) => println!("Ошибка: {}", e),
        }
    }
    
    // Тестирование адресов сокетов
    let socket_str = "127.0.0.1:8080";
    match parse_socket_address(socket_str) {
        Ok(addr) => println!("Успешно разобран адрес сокета: {}", addr),
        Err(e) => println!("Ошибка: {}", e),
    }
}

Создание пользовательских парсеров с детальной обработкой ошибок

use std::net::{IpAddr, AddrParseError};
use std::str::FromStr;
use std::error::Error;

#[derive(Debug)]
struct NetworkConfig {
    ip: IpAddr,
    port: u16,
}

impl NetworkConfig {
    fn from_str(s: &str) -> Result<Self, Box<dyn Error>> {
        let parts: Vec<&str> = s.split(':').collect();
        
        if parts.len() != 2 {
            return Err("Ожидается формат 'IP:PORT'".into());
        }
        
        let ip = IpAddr::from_str(parts[0])
            .map_err(|e: AddrParseError| {
                format!("Неверный IP-адрес '{}': {}", parts[0], e)
            })?;
            
        let port = parts[1].parse::<u16>()
            .map_err(|e| {
                format!("Неверный порт '{}': {}", parts[1], e)
            })?;
            
        Ok(NetworkConfig { ip, port })
    }
}

fn main() {
    let test_cases = [
        "127.0.0.1:8080",
        "::1:9000",
        "invalid_ip:8080",
        "192.168.1.1:99999", // Неверный порт
        "no_colon", // Отсутствует разделитель
    ];
    
    for test_case in &test_cases {
        println!("Разбор '{}':", test_case);
        match NetworkConfig::from_str(test_case) {
            Ok(config) => println!("  Успех: IP={}, PORT={}", config.ip, config.port),
            Err(e) => println!("  Ошибка: {}", e),
        }
        println!();
    }
}

Валидация пользовательского ввода

use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;

fn validate_user_input(input: &str) -> Result<(), String> {
    // Попробуем разобрать как IP-адрес
    if let Ok(ip) = IpAddr::from_str(input) {
        if ip.is_loopback() {
            return Err("IP-адрес обратной петли не разрешен".to_string());
        }
        if ip.is_unspecified() {
            return Err("Неспецифицированный IP-адрес не разрешен".to_string());
        }
        println!("Валидный IP-адрес: {}", ip);
        return Ok(());
    }
    
    // Попробуем разобрать как адрес сокета
    if let Ok(socket) = SocketAddr::from_str(input) {
        if socket.port() == 0 {
            return Err("Порт 0 не разрешен".to_string());
        }
        println!("Валидный адрес сокета: {}", socket);
        return Ok(());
    }
    
    Err(format!("'{}' не является валидным IP-адресом или адресом сокета", input))
}

fn main() {
    let inputs = [
        "127.0.0.1",
        "192.168.1.1",
        "0.0.0.0",
        "google.com:80",
        "256.256.256.256",
        "localhost:8080",
        "123.45.67.89:0",
    ];
    
    for input in &inputs {
        println!("Валидация '{}':", input);
        match validate_user_input(input) {
            Ok(()) => println!("  ✓ Валидный ввод"),
            Err(e) => println!("  ✗ Ошибка: {}", e),
        }
    }
}

Интеграция с другими типами ошибок

use std::net::{IpAddr, AddrParseError};
use std::str::FromStr;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum ConfigError {
    #[error("Ошибка анализа IP-адреса '{input}': {source}")]
    AddrParse {
        input: String,
        source: AddrParseError,
    },
    
    #[error("Ошибка ввода-вывода: {0}")]
    Io(#[from] std::io::Error),
    
    #[error("Неверный формат конфигурации: {0}")]
    InvalidFormat(String),
}

pub fn parse_ip_with_detailed_error(ip_str: &str) -> Result<IpAddr, ConfigError> {
    IpAddr::from_str(ip_str)
        .map_err(|source| ConfigError::AddrParse {
            input: ip_str.to_string(),
            source,
        })
}

pub fn load_config_from_file(filename: &str, ip_str: &str) -> Result<(), ConfigError> {
    // Имитация чтения файла
    println!("Чтение конфигурации из {}", filename);
    
    // Разбор IP-адреса с детализированной ошибкой
    let ip = parse_ip_with_detailed_error(ip_str)?;
    
    println!("Загружена конфигурация с IP: {}", ip);
    Ok(())
}

fn main() {
    let test_cases = [
        ("config1.txt", "192.168.1.1"),
        ("config2.txt", "invalid_ip"),
        ("config3.txt", "999.999.999.999"),
    ];
    
    for (filename, ip_str) in &test_cases {
        println!("Обработка {} с IP {}", filename, ip_str);
        match load_config_from_file(filename, ip_str) {
            Ok(()) => println!("  ✓ Успех"),
            Err(e) => println!("  ✗ Ошибка: {}", e),
        }
        println!();
    }
}

Утилитарные функции для работы с ошибками анализа

use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, AddrParseError};
use std::str::FromStr;

fn analyze_parse_error(input: &str) {
    println!("Анализ ошибки для '{}':", input);
    
    // Проверяем различные типы адресов
    match IpAddr::from_str(input) {
        Ok(ip) => println!("  ✓ Валидный IP-адрес: {}", ip),
        Err(e) => {
            println!("  ✗ Ошибка анализа IP: {}", e);
            
            // Детальный анализ
            if let Ok(ipv4) = Ipv4Addr::from_str(input) {
                println!("  - Но это валидный IPv4: {}", ipv4);
            } else if let Ok(ipv6) = Ipv6Addr::from_str(input) {
                println!("  - Но это валидный IPv6: {}", ipv6);
            } else {
                println!("  - Не является валидным ни IPv4, ни IPv6");
            }
        }
    }
}

fn suggest_correction(input: &str) -> Option<String> {
    // Простые эвристики для предложения исправлений
    let trimmed = input.trim();
    
    // Убираем лишние пробелы
    if trimmed != input {
        return Some(trimmed.to_string());
    }
    
    // Проверяем IPv6 без скобок
    if trimmed.contains(':') && !trimmed.starts_with('[') {
        let suggestion = format!("[{}]", trimmed);
        if IpAddr::from_str(&suggestion).is_ok() {
            return Some(suggestion);
        }
    }
    
    None
}

fn main() {
    let problematic_inputs = [
        " 127.0.0.1 ", // Лишние пробелы
        "::1",         // IPv6 без скобок для адреса сокета
        "192.168.001.001", // Ведущие нули
        "fe80::1%eth0", // IPv6 с зоной
    ];
    
    for input in &problematic_inputs {
        analyze_parse_error(input);
        
        if let Some(suggestion) = suggest_correction(input) {
            println!("  💡 Предложение: попробуйте '{}'", suggestion);
            
            if IpAddr::from_str(&suggestion).is_ok() {
                println!("  ✅ Предложение работает!");
            }
        }
        println!();
    }
}

Распространенные сценарии ошибок

Неверные IPv4 адреса

  • "256.256.256.256" - октеты больше 255
  • "192.168.1" - недостаточно октетов
  • "192.168.1.1.1" - слишком много октетов
  • "192.168.1." - незавершенный адрес

Неверные IPv6 адреса

  • "::fffff" - неверный формат
  • "2001:db8::1::1" - множественные ::
  • "2001:db8:xyz::1" - неверные шестнадцатеричные цифры

Неверные адреса сокетов

  • "127.0.0.1:" - отсутствует порт
  • "127.0.0.1:99999" - порт вне диапазона
  • "[::1]" - IPv6 без порта