use std::{
fmt,
hash::{Hash, Hasher},
ptr::NonNull,
};
use bitflags::bitflags;
use cxx::ExternType;
#[cfg(feature = "proto")]
mod actor;
pub mod config;
mod encoded;
#[cfg(feature = "proto")]
pub mod proto;
mod traffic;
#[cfg(feature = "proto")]
pub use actor::{Actor, Response};
pub use config::Config;
pub use config::ConfigBuilder;
pub use encoded::Shape;
pub use ffi::AdminInfo;
pub use ffi::EdgeInfo;
pub use ffi::EdgeUse;
pub use ffi::NodeType;
pub use ffi::RoadClass;
pub use ffi::TileId;
pub use ffi::TimeZoneInfo;
pub use ffi::TrafficTile;
pub use ffi::decode_weekly_speeds;
pub use ffi::encode_weekly_speeds;
pub use traffic::{LiveTraffic, TrafficSegment};
#[cxx::bridge]
mod ffi {
#[namespace = "valhalla::baldr"]
#[cxx_name = "Use"]
#[repr(u8)]
#[derive(Debug)]
enum EdgeUse {
kRoad = 0,
kRamp = 1, kTurnChannel = 2, kTrack = 3, kDriveway = 4, kAlley = 5, kParkingAisle = 6, kEmergencyAccess = 7, kDriveThru = 8, kCuldesac = 9, kLivingStreet = 10, kServiceRoad = 11,
kCycleway = 20, kMountainBike = 21,
kSidewalk = 24,
kFootway = 25,
kSteps = 26, kPath = 27,
kPedestrian = 28,
kBridleway = 29,
kPedestrianCrossing = 32, kElevator = 33,
kEscalator = 34,
kPlatform = 35,
kRestArea = 30,
kServiceArea = 31,
kOther = 40,
kFerry = 41,
kRailFerry = 42,
kConstruction = 43,
kRail = 50, kBus = 51, kEgressConnection = 52, kPlatformConnection = 53, kTransitConnection = 54, }
#[namespace = "valhalla::baldr"]
#[repr(u8)]
#[derive(Debug, PartialOrd, Ord)]
enum RoadClass {
kMotorway = 0,
kTrunk = 1,
kPrimary = 2,
kSecondary = 3,
kTertiary = 4,
kUnclassified = 5,
kResidential = 6,
kServiceOther = 7,
kInvalid = 8,
}
#[namespace = "valhalla::baldr"]
#[repr(u8)]
#[derive(Debug)]
enum NodeType {
kStreetIntersection = 0,
kGate = 1,
kBollard = 2,
kTollBooth = 3,
kTransitEgress = 4,
kTransitStation = 5,
kMultiUseTransitPlatform = 6,
kBikeShare = 7,
kParking = 8,
kMotorWayJunction = 9,
kBorderControl = 10,
kTollGantry = 11,
kSumpBuster = 12,
kBuildingEntrance = 13,
kElevator = 14,
}
#[derive(Clone, Copy)]
struct EdgeInfo<'a> {
way_id: u64,
speed_limit: u8,
encoded_shape: &'a [u8],
}
struct LatLon {
lat: f64,
lon: f64,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct TileId {
value: u32,
}
#[derive(Clone)]
struct AdminInfo {
country_text: String,
state_text: String,
country_iso: String,
state_iso: String,
}
#[derive(Clone)]
struct TimeZoneInfo {
name: String,
offset_seconds: i32,
}
struct TrafficTile {
header: *mut u64,
speeds: *mut u64,
edge_count: u32,
traffic_tar: SharedPtr<tar>,
}
unsafe extern "C++" {
include!("valhalla/src/libvalhalla.hpp");
#[namespace = "valhalla::baldr"]
type GraphId = crate::GraphId;
fn from_parts(level: u8, tile_index: u32, id: u32) -> Result<GraphId>;
#[namespace = "boost::property_tree"]
type ptree = crate::config::ffi::ptree;
type TileSet;
fn new_tileset(config: &ptree) -> Result<SharedPtr<TileSet>>;
fn tiles(self: &TileSet) -> Vec<TileId>;
fn tiles_in_bbox(
self: &TileSet,
min_lat: f32,
min_lon: f32,
max_lat: f32,
max_lon: f32,
level: u8,
) -> Vec<TileId>;
fn get_graph_tile(self: &TileSet, id: TileId) -> *const GraphTile;
fn get_traffic_tile(self: &TileSet, id: TileId) -> Result<TrafficTile>;
fn dataset_id(self: &TileSet) -> u64;
#[namespace = "valhalla::baldr"]
type GraphTile;
unsafe fn add_ref(tile: *const GraphTile);
unsafe fn release(tile: *const GraphTile);
fn id(self: &GraphTile) -> GraphId;
fn directededges(tile: &GraphTile) -> &[DirectedEdge];
fn directededge(self: &GraphTile, index: usize) -> Result<*const DirectedEdge>;
fn edgeinfo<'a>(tile: &'a GraphTile, de: &DirectedEdge) -> EdgeInfo<'a>;
fn nodes(tile: &GraphTile) -> &[NodeInfo];
fn node(self: &GraphTile, index: usize) -> Result<*const NodeInfo>;
fn node_edges<'a>(tile: &'a GraphTile, node: &NodeInfo) -> &'a [DirectedEdge];
fn node_transitions<'a>(tile: &'a GraphTile, node: &NodeInfo) -> &'a [NodeTransition];
fn node_latlon(tile: &GraphTile, node: &NodeInfo) -> LatLon;
fn admininfo(tile: &GraphTile, index: u32) -> Result<AdminInfo>;
unsafe fn GetSpeed(
self: &GraphTile,
de: *const DirectedEdge,
flow_mask: u8,
seconds: u64,
is_truck: bool,
flow_sources: *mut u8,
seconds_from_now: u64,
) -> u32;
fn live_traffic(tile: &GraphTile, de: &DirectedEdge) -> u64;
#[namespace = "valhalla::midgard"]
type tar;
fn id(tile: &TrafficTile) -> GraphId;
fn last_update(tile: &TrafficTile) -> u64;
fn write_last_update(tile: &TrafficTile, unix_timestamp: u64);
fn spare(tile: &TrafficTile) -> u64;
fn write_spare(tile: &TrafficTile, spare: u64);
#[namespace = "valhalla::baldr"]
#[cxx_name = "Use"]
type EdgeUse;
#[namespace = "valhalla::baldr"]
type RoadClass;
#[namespace = "valhalla::baldr"]
type NodeType;
#[namespace = "valhalla::baldr"]
type DirectedEdge = crate::DirectedEdge;
fn endnode(self: &DirectedEdge) -> GraphId;
fn opp_index(self: &DirectedEdge) -> u32;
fn forward(self: &DirectedEdge) -> bool;
#[cxx_name = "use"]
fn use_type(self: &DirectedEdge) -> EdgeUse;
#[cxx_name = "classification"]
fn road_class(self: &DirectedEdge) -> RoadClass;
fn length(self: &DirectedEdge) -> u32;
fn toll(self: &DirectedEdge) -> bool;
fn destonly(self: &DirectedEdge) -> bool;
fn tunnel(self: &DirectedEdge) -> bool;
fn bridge(self: &DirectedEdge) -> bool;
fn roundabout(self: &DirectedEdge) -> bool;
#[cxx_name = "ctry_crossing"]
fn crosses_country_border(self: &DirectedEdge) -> bool;
#[cxx_name = "forwardaccess"]
fn forwardaccess_u32(self: &DirectedEdge) -> u32;
#[cxx_name = "reverseaccess"]
fn reverseaccess_u32(self: &DirectedEdge) -> u32;
fn speed(self: &DirectedEdge) -> u32;
fn truck_speed(self: &DirectedEdge) -> u32;
fn free_flow_speed(self: &DirectedEdge) -> u32;
fn constrained_flow_speed(self: &DirectedEdge) -> u32;
fn is_shortcut(self: &DirectedEdge) -> bool;
fn leaves_tile(self: &DirectedEdge) -> bool;
#[namespace = "valhalla::baldr"]
type NodeInfo = crate::NodeInfo;
fn edge_index(self: &NodeInfo) -> u32;
fn edge_count(self: &NodeInfo) -> u32;
#[cxx_name = "type"]
fn node_type(self: &NodeInfo) -> NodeType;
fn elevation(self: &NodeInfo) -> f32;
#[cxx_name = "access"]
fn access_u16(self: &NodeInfo) -> u16;
fn private_access(self: &NodeInfo) -> bool;
fn admin_index(self: &NodeInfo) -> u32;
fn timezone(self: &NodeInfo) -> u32;
fn density(self: &NodeInfo) -> u32;
fn transition_index(self: &NodeInfo) -> u32;
fn transition_count(self: &NodeInfo) -> u32;
fn from_id(id: u32, unix_timestamp: u64) -> Result<TimeZoneInfo>;
#[namespace = "valhalla::baldr"]
type NodeTransition = crate::NodeTransition;
fn endnode(self: &NodeTransition) -> GraphId;
#[cxx_name = "up"]
fn upward(self: &NodeTransition) -> bool;
fn encode_weekly_speeds(speeds: &[f32]) -> Result<String>;
fn decode_weekly_speeds(encoded: &str) -> Result<Vec<f32>>;
}
}
unsafe impl Send for ffi::TileSet {}
unsafe impl Sync for ffi::TileSet {}
#[derive(Clone, Copy, Eq)]
#[repr(C)]
pub struct GraphId {
pub value: u64,
}
unsafe impl ExternType for GraphId {
type Id = cxx::type_id!("valhalla::baldr::GraphId");
type Kind = cxx::kind::Trivial;
}
impl Default for GraphId {
#[inline(always)]
fn default() -> Self {
Self {
value: 0x3fffffffffff,
}
}
}
impl fmt::Debug for GraphId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("GraphId")
.field("level", &self.level())
.field("tile_index", &self.tile_index())
.field("id", &self.id())
.finish()
}
}
impl fmt::Display for GraphId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}/{}/{}", self.level(), self.tile_index(), self.id())
}
}
impl PartialEq for GraphId {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl Hash for GraphId {
fn hash<H: Hasher>(&self, state: &mut H) {
self.value.hash(state);
}
}
impl GraphId {
#[inline(always)]
pub fn new(value: u64) -> Self {
Self { value }
}
#[inline(always)]
pub fn from_parts(level: u8, tile_index: u32, id: u32) -> Option<Self> {
ffi::from_parts(level, tile_index, id).ok()
}
#[inline(always)]
pub fn level(&self) -> u8 {
(self.value & 0x7) as u8
}
#[inline(always)]
pub fn tile_index(&self) -> u32 {
((self.value & 0x1fffff8) >> 3) as u32
}
#[inline(always)]
pub fn tile(&self) -> TileId {
TileId {
value: (self.value & 0x1ffffff) as u32,
}
}
#[inline(always)]
pub fn id(&self) -> u32 {
((self.value & 0x3ffffe000000) >> 25) as u32
}
}
impl TileId {
#[inline(always)]
pub fn level(&self) -> u8 {
(self.value & 0x7) as u8
}
#[inline(always)]
pub fn tile_index(&self) -> u32 {
self.value >> 3
}
#[inline(always)]
pub fn graph_id(&self, id: u32) -> Option<GraphId> {
GraphId::from_parts(self.level(), self.tile_index(), id)
}
}
impl Default for TileId {
#[inline(always)]
fn default() -> Self {
GraphId::default().tile()
}
}
impl From<GraphId> for TileId {
#[inline(always)]
fn from(id: GraphId) -> Self {
id.tile()
}
}
impl fmt::Debug for TileId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TileId")
.field("level", &self.level())
.field("tile_index", &self.tile_index())
.finish()
}
}
impl fmt::Display for TileId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}/{}", self.level(), self.tile_index())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Error(Box<str>);
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.0)
}
}
impl std::error::Error for Error {}
impl From<cxx::Exception> for Error {
fn from(err: cxx::Exception) -> Self {
Error(err.what().into())
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Access: u16 {
const AUTO = 1;
const PEDESTRIAN = 2;
const BICYCLE = 4;
const TRUCK = 8;
const EMERGENCY = 16;
const TAXI = 32;
const BUS = 64;
const HOV = 128;
const WHEELCHAIR = 256;
const MOPED = 512;
const MOTORCYCLE = 1024;
const ALL = 4095;
const VEHICULAR = Self::AUTO.bits() | Self::TRUCK.bits() | Self::MOPED.bits() | Self::MOTORCYCLE.bits()
| Self::TAXI.bits() | Self::BUS.bits() | Self::HOV.bits();
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SpeedSources: u8 {
const NO_FLOW = 0;
const FREE_FLOW = 1;
const CONSTRAINED_FLOW = 2;
const PREDICTED_FLOW = 4;
const CURRENT_FLOW = 8;
const ALL = Self::FREE_FLOW.bits() | Self::CONSTRAINED_FLOW.bits()
| Self::PREDICTED_FLOW.bits() | Self::CURRENT_FLOW.bits();
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct LatLon(pub f64, pub f64);
#[cfg(feature = "proto")]
impl From<LatLon> for proto::LatLng {
fn from(loc: LatLon) -> Self {
proto::LatLng {
has_lat: Some(proto::lat_lng::HasLat::Lat(loc.0)),
has_lng: Some(proto::lat_lng::HasLng::Lng(loc.1)),
}
}
}
#[cfg(feature = "proto")]
impl From<LatLon> for Option<proto::LatLng> {
fn from(loc: LatLon) -> Self {
Some(loc.into())
}
}
#[derive(Clone)]
pub struct GraphReader(cxx::SharedPtr<ffi::TileSet>);
impl GraphReader {
pub fn new(config: &Config) -> Result<Self, Error> {
Ok(Self(ffi::new_tileset(config.inner())?))
}
pub fn dataset_id(&self) -> u64 {
self.0.dataset_id()
}
pub fn tiles(&self) -> Vec<TileId> {
self.0.tiles()
}
pub fn tiles_in_bbox(&self, min: LatLon, max: LatLon, level: u8) -> Vec<TileId> {
self.0.tiles_in_bbox(
min.0 as f32,
min.1 as f32,
max.0 as f32,
max.1 as f32,
level,
)
}
pub fn graph_tile(&self, id: impl Into<TileId>) -> Option<GraphTile> {
GraphTile::new(self.0.get_graph_tile(id.into()))
}
pub fn traffic_tile(&self, id: impl Into<TileId>) -> Option<ffi::TrafficTile> {
self.0.get_traffic_tile(id.into()).ok()
}
}
pub struct GraphTile(NonNull<ffi::GraphTile>);
impl Clone for GraphTile {
fn clone(&self) -> Self {
unsafe { ffi::add_ref(self.0.as_ptr()) };
Self(self.0)
}
}
impl Drop for GraphTile {
fn drop(&mut self) {
unsafe { ffi::release(self.0.as_ptr()) };
}
}
impl GraphTile {
fn new(tile: *const ffi::GraphTile) -> Option<Self> {
NonNull::new(tile.cast_mut()).map(Self)
}
fn deref(&self) -> &ffi::GraphTile {
unsafe { self.0.as_ref() }
}
#[inline(always)]
pub fn id(&self) -> TileId {
self.deref().id().tile()
}
#[inline(always)]
pub fn directededges(&self) -> &[ffi::DirectedEdge] {
ffi::directededges(self.deref())
}
pub fn directededge(&self, index: u32) -> Option<&ffi::DirectedEdge> {
match self.deref().directededge(index as usize) {
Ok(ptr) if !ptr.is_null() => Some(unsafe { &*ptr }),
_ => None,
}
}
#[inline(always)]
pub fn nodes(&self) -> &[ffi::NodeInfo] {
ffi::nodes(self.deref())
}
pub fn node(&self, index: u32) -> Option<&ffi::NodeInfo> {
match self.deref().node(index as usize) {
Ok(ptr) if !ptr.is_null() => Some(unsafe { &*ptr }),
_ => None,
}
}
#[inline(always)]
pub fn node_latlon(&self, node: &ffi::NodeInfo) -> LatLon {
debug_assert!(ref_within_slice(self.nodes(), node), "Wrong tile");
let latlon = ffi::node_latlon(self.deref(), node);
LatLon(latlon.lat, latlon.lon)
}
#[inline(always)]
pub fn node_edges<'a>(&'a self, node: &ffi::NodeInfo) -> &'a [ffi::DirectedEdge] {
debug_assert!(ref_within_slice(self.nodes(), node), "Wrong tile");
ffi::node_edges(self.deref(), node)
}
#[inline(always)]
pub fn node_transitions<'a>(&'a self, node: &ffi::NodeInfo) -> &'a [ffi::NodeTransition] {
debug_assert!(ref_within_slice(self.nodes(), node), "Wrong tile");
ffi::node_transitions(self.deref(), node)
}
pub fn admin_info(&self, index: u32) -> Option<ffi::AdminInfo> {
ffi::admininfo(self.deref(), index).ok()
}
#[inline(always)]
pub fn edgeinfo<'a>(&'a self, de: &ffi::DirectedEdge) -> EdgeInfo<'a> {
debug_assert!(ref_within_slice(self.directededges(), de), "Wrong tile");
ffi::edgeinfo(self.deref(), de)
}
#[inline(always)]
pub fn live_traffic(&self, de: &ffi::DirectedEdge) -> LiveTraffic {
debug_assert!(ref_within_slice(self.directededges(), de), "Wrong tile");
LiveTraffic::from_bits(ffi::live_traffic(self.deref(), de))
}
pub fn edge_speed(
&self,
de: &ffi::DirectedEdge,
speed_sources: SpeedSources,
is_truck: bool,
second_of_week: u64,
seconds_from_now: u64,
) -> (u32, SpeedSources) {
debug_assert!(ref_within_slice(self.directededges(), de), "Wrong tile");
let mut flow_sources: u8 = 0;
let speed = unsafe {
self.deref().GetSpeed(
de as *const ffi::DirectedEdge,
speed_sources.bits(),
second_of_week,
is_truck,
&mut flow_sources,
seconds_from_now,
)
};
(speed, SpeedSources::from_bits_retain(flow_sources))
}
}
#[repr(C)]
pub struct DirectedEdge {
data: [u64; 6],
}
unsafe impl ExternType for DirectedEdge {
type Id = cxx::type_id!("valhalla::baldr::DirectedEdge");
type Kind = cxx::kind::Trivial;
}
impl DirectedEdge {
#[inline(always)]
pub fn forwardaccess(&self) -> Access {
Access::from_bits_retain(self.forwardaccess_u32() as u16)
}
#[inline(always)]
pub fn reverseaccess(&self) -> Access {
Access::from_bits_retain(self.reverseaccess_u32() as u16)
}
}
#[repr(C)]
pub struct NodeInfo {
data: [u64; 4],
}
unsafe impl ExternType for NodeInfo {
type Id = cxx::type_id!("valhalla::baldr::NodeInfo");
type Kind = cxx::kind::Trivial;
}
impl NodeInfo {
#[inline(always)]
pub fn access(&self) -> Access {
Access::from_bits_retain(self.access_u16())
}
}
#[repr(C)]
pub struct NodeTransition {
data: [u64; 1],
}
unsafe impl ExternType for NodeTransition {
type Id = cxx::type_id!("valhalla::baldr::NodeTransition");
type Kind = cxx::kind::Trivial;
}
impl TimeZoneInfo {
#[inline(always)]
pub fn from_id(id: u32, unix_timestamp: u64) -> Option<Self> {
ffi::from_id(id, unix_timestamp).ok()
}
}
impl<'a> EdgeInfo<'a> {
#[inline(always)]
pub fn shape(&self) -> Shape<'a> {
Shape::new(self.encoded_shape)
}
}
fn ref_within_slice<T>(slice: &[T], item: &T) -> bool {
let start = slice.as_ptr() as usize;
let item_pos = item as *const T as usize;
let byte_offset = item_pos.wrapping_sub(start);
byte_offset < std::mem::size_of_val(slice)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn graph_id() {
let id = GraphId::new(5411833275938);
assert_eq!(id.level(), 2);
assert_eq!(id.tile_index(), 838852);
assert_eq!(id.id(), 161285);
assert_eq!(
GraphId::from_parts(id.level(), id.tile_index(), id.id()),
Some(id)
);
assert_eq!(format!("{id}"), "2/838852/161285");
assert_eq!(
format!("{id:?}"),
"GraphId { level: 2, tile_index: 838852, id: 161285 }"
);
let default_id = GraphId::default();
assert_eq!(default_id.level(), 7);
assert_eq!(default_id.tile_index(), 4194303);
assert_eq!(default_id.id(), 2097151);
assert_eq!(GraphId::from_parts(8, id.tile_index(), 0), None);
}
#[test]
fn tile_id() {
let id = GraphId::new(5411833275938);
let tile = id.tile();
assert_eq!(tile, TileId::from(id));
assert_eq!(tile.level(), 2);
assert_eq!(tile.tile_index(), 838852);
assert_eq!(format!("{tile}"), "2/838852");
assert_eq!(
format!("{tile:?}"),
"TileId { level: 2, tile_index: 838852 }"
);
assert_eq!(tile.graph_id(id.id()), Some(id));
assert_eq!(tile.graph_id(0).map(|base| base.tile()), Some(tile));
assert_eq!(tile.graph_id(0).map(|base| base.id()), Some(0));
assert_eq!(tile.graph_id(1 << 21), None);
assert_eq!(tile.value, (id.value & 0x1ffffff) as u32);
let invalid = TileId::default();
assert_eq!(invalid.level(), 7);
assert_eq!(invalid.tile_index(), 4194303);
}
#[test]
fn test_ref_within_slice() {
let data = [10, 20, 30, 40, 50];
assert!(ref_within_slice(&data, &data[0]));
assert!(ref_within_slice(&data, &data[2]));
assert!(ref_within_slice(&data, &data[4]));
let outside = 30;
assert!(!ref_within_slice(&data, &outside));
let subslice = &data[1..4];
assert!(!ref_within_slice(subslice, &data[0]));
assert!(ref_within_slice(subslice, &data[1]));
assert!(ref_within_slice(subslice, &data[2]));
assert!(ref_within_slice(subslice, &data[3]));
assert!(!ref_within_slice(subslice, &data[4]));
}
}