Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
description = "Read GTFS (public transit timetables) files"
name = "gtfs-structures"
version = "0.44.0"
version = "0.45.0"
authors = [
"Tristram Gräbener <tristramg@gmail.com>",
"Antoine Desbordes <antoine.desbordes@gmail.com>",
Expand Down
32 changes: 23 additions & 9 deletions src/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,20 +340,20 @@ pub struct Route {
pub order: Option<u32>,
/// Route color designation that matches public facing material
#[serde(
deserialize_with = "deserialize_route_color",
serialize_with = "serialize_color",
deserialize_with = "deserialize_optional_color",
serialize_with = "serialize_optional_color",
rename = "route_color",
default = "default_route_color"
default
)]
pub color: RGB8,
pub color: Option<RGB8>,
/// Legible color to use for text drawn against a background of [Route::route_color]
#[serde(
deserialize_with = "deserialize_route_text_color",
serialize_with = "serialize_color",
deserialize_with = "deserialize_optional_color",
serialize_with = "serialize_optional_color",
rename = "route_text_color",
default
)]
pub text_color: RGB8,
pub text_color: Option<RGB8>,
/// Indicates whether a rider can board the transit vehicle anywhere along the vehicle’s travel path
#[serde(default)]
pub continuous_pickup: ContinuousPickupDropOff,
Expand All @@ -362,6 +362,20 @@ pub struct Route {
pub continuous_drop_off: ContinuousPickupDropOff,
}

impl Route {
/// Legible color to use for text drawn against a background of [Route::route_color]
/// Defaults to white (FFFFFF) when omitted or left empty.
pub fn text_color(&self) -> RGB8 {
self.text_color.unwrap_or_default()
}

/// Legible color to use for text drawn against a background of [Route::route_color]
/// Defaults to black (000000) when omitted or left empty.
pub fn color(&self) -> RGB8 {
self.color.unwrap_or_else(default_route_color)
}
}

impl Type for Route {
fn object_type(&self) -> ObjectType {
ObjectType::Route
Expand All @@ -377,9 +391,9 @@ impl Id for Route {
impl fmt::Display for Route {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(long_name) = self.long_name.as_ref() {
write!(f, "{}", long_name)
write!(f, "{long_name}")
} else if let Some(short_name) = self.short_name.as_ref() {
write!(f, "{}", short_name)
write!(f, "{short_name}")
} else {
write!(f, "{}", self.id)
}
Expand Down
30 changes: 11 additions & 19 deletions src/serde_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,7 @@ where
}
}

pub fn parse_color(
s: &str,
default: impl std::ops::FnOnce() -> RGB8,
) -> Result<RGB8, crate::Error> {
if s.is_empty() {
return Ok(default());
}
pub fn parse_color(s: &str) -> Result<RGB8, crate::Error> {
if s.len() != 6 {
return Err(crate::Error::InvalidColor(s.to_owned()));
}
Expand All @@ -158,26 +152,24 @@ pub fn parse_color(
Ok(RGB8::new(r, g, b))
}

pub fn deserialize_route_color<'de, D>(de: D) -> Result<RGB8, D::Error>
where
D: Deserializer<'de>,
{
String::deserialize(de)
.and_then(|s| parse_color(&s, default_route_color).map_err(de::Error::custom))
}

pub fn deserialize_route_text_color<'de, D>(de: D) -> Result<RGB8, D::Error>
pub fn deserialize_optional_color<'de, D>(de: D) -> Result<Option<RGB8>, D::Error>
where
D: Deserializer<'de>,
{
String::deserialize(de).and_then(|s| parse_color(&s, RGB8::default).map_err(de::Error::custom))
Option::<&str>::deserialize(de)?
.map(|s| parse_color(s).map_err(de::Error::custom))
.transpose()
}

pub fn serialize_color<S>(color: &RGB8, serializer: S) -> Result<S::Ok, S::Error>
pub fn serialize_optional_color<S>(color: &Option<RGB8>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(format!("{:02X}{:02X}{:02X}", color.r, color.g, color.b).as_str())
match color {
Some(color) => serializer
.serialize_str(format!("{:02X}{:02X}{:02X}", color.r, color.g, color.b).as_str()),
None => serializer.serialize_none(),
}
}

pub fn default_route_color() -> RGB8 {
Expand Down
14 changes: 7 additions & 7 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,19 @@ fn read_routes() {
let gtfs = Gtfs::from_path("fixtures/basic").expect("impossible to read gtfs");
assert_eq!(3, gtfs.routes.len());
assert_eq!(RouteType::Bus, gtfs.get_route("1").unwrap().route_type);
assert_eq!(RGB8::new(0, 0, 0), gtfs.get_route("1").unwrap().color);
assert_eq!(RGB8::new(0, 0, 0), gtfs.get_route("1").unwrap().color());
assert_eq!(
RGB8::new(255, 255, 255),
gtfs.get_route("1").unwrap().text_color
gtfs.get_route("1").unwrap().text_color()
);
assert_eq!(RGB8::new(0, 0, 0), gtfs.get_route("1").unwrap().color);
assert_eq!(RGB8::new(0, 0, 0), gtfs.get_route("1").unwrap().color());
assert_eq!(
RGB8::new(0, 0, 0),
gtfs.get_route("default_colors").unwrap().text_color
gtfs.get_route("default_colors").unwrap().text_color()
);
assert_eq!(
RGB8::new(255, 255, 255),
gtfs.get_route("default_colors").unwrap().color
gtfs.get_route("default_colors").unwrap().color()
);
assert_eq!(Some(1), gtfs.get_route("1").unwrap().order);
assert_eq!(
Expand Down Expand Up @@ -440,8 +440,8 @@ fn read_only_required_fields() {
let fare_attribute = gtfs.fare_attributes.get("50").unwrap();
let feed = &gtfs.feed_info[0];
let shape = &gtfs.shapes.get("A_shp").unwrap()[0];
assert_eq!(route.color, RGB8::new(255, 255, 255));
assert_eq!(route.text_color, RGB8::new(0, 0, 0));
assert_eq!(route.color(), RGB8::new(255, 255, 255));
assert_eq!(route.text_color(), RGB8::new(0, 0, 0));
assert_eq!(fare_attribute.transfer_duration, None);
assert_eq!(feed.start_date, None);
assert_eq!(feed.end_date, None);
Expand Down