use std::fmt;
#[derive(Debug, Clone)]
pub enum RouteMatchError {
InsufficientPoints {
activity_id: String,
point_count: usize,
minimum_required: usize,
},
InvalidCoordinates {
activity_id: String,
message: String,
},
RouteTooShort {
activity_id: String,
distance: f64,
minimum_required: f64,
},
SectionDetectionFailed { message: String },
OverlapDetectionFailed { message: String },
PersistenceError { message: String },
HttpError {
message: String,
status_code: Option<u16>,
},
ConfigError { message: String },
SpatialIndexError { message: String },
Internal { message: String },
}
impl fmt::Display for RouteMatchError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RouteMatchError::InsufficientPoints {
activity_id,
point_count,
minimum_required,
} => {
write!(
f,
"Route '{}' has {} points, minimum {} required",
activity_id, point_count, minimum_required
)
}
RouteMatchError::InvalidCoordinates {
activity_id,
message,
} => {
write!(
f,
"Route '{}' has invalid coordinates: {}",
activity_id, message
)
}
RouteMatchError::RouteTooShort {
activity_id,
distance,
minimum_required,
} => {
write!(
f,
"Route '{}' is {:.0}m, minimum {:.0}m required",
activity_id, distance, minimum_required
)
}
RouteMatchError::SectionDetectionFailed { message } => {
write!(f, "Section detection failed: {}", message)
}
RouteMatchError::OverlapDetectionFailed { message } => {
write!(f, "Overlap detection failed: {}", message)
}
RouteMatchError::PersistenceError { message } => {
write!(f, "Persistence error: {}", message)
}
RouteMatchError::HttpError {
message,
status_code,
} => {
if let Some(code) = status_code {
write!(f, "HTTP error ({}): {}", code, message)
} else {
write!(f, "HTTP error: {}", message)
}
}
RouteMatchError::ConfigError { message } => {
write!(f, "Configuration error: {}", message)
}
RouteMatchError::SpatialIndexError { message } => {
write!(f, "Spatial index error: {}", message)
}
RouteMatchError::Internal { message } => {
write!(f, "Internal error: {}", message)
}
}
}
}
impl std::error::Error for RouteMatchError {}
pub type Result<T> = std::result::Result<T, RouteMatchError>;
pub trait OptionExt<T> {
fn ok_or_insufficient_points(
self,
activity_id: &str,
point_count: usize,
minimum: usize,
) -> Result<T>;
fn ok_or_internal(self, message: &str) -> Result<T>;
}
impl<T> OptionExt<T> for Option<T> {
fn ok_or_insufficient_points(
self,
activity_id: &str,
point_count: usize,
minimum: usize,
) -> Result<T> {
self.ok_or_else(|| RouteMatchError::InsufficientPoints {
activity_id: activity_id.to_string(),
point_count,
minimum_required: minimum,
})
}
fn ok_or_internal(self, message: &str) -> Result<T> {
self.ok_or_else(|| RouteMatchError::Internal {
message: message.to_string(),
})
}
}