1pub mod air;
2pub mod bus;
3pub mod located;
4pub mod rail;
5pub mod sea;
6pub mod spawn_warp;
7pub mod town;
8
9use enum_dispatch::enum_dispatch;
10use rusqlite::OptionalExtension;
11use strum_macros::{EnumIs, EnumTryAs};
12
13use crate::{
14 error::Result,
15 node::{
16 air::{AirAirline, AirAirport, AirFlight, AirGate},
17 bus::{BusBerth, BusCompany, BusConnection, BusLine, BusStop},
18 located::AnyLocatedNode,
19 rail::{RailCompany, RailConnection, RailLine, RailPlatform, RailStation},
20 sea::{SeaCompany, SeaConnection, SeaDock, SeaLine, SeaStop},
21 spawn_warp::SpawnWarp,
22 town::Town,
23 },
24 util::ID,
25 GD,
26};
27
28#[enum_dispatch]
29pub trait Node: Copy {
30 fn i(self) -> ID;
31 fn ty(self) -> &'static str;
32}
33
34#[enum_dispatch(Node)]
35#[derive(Clone, Copy, PartialEq, Eq, Debug, EnumIs, EnumTryAs)]
36pub enum AnyNode {
37 AirAirline,
38 AirAirport,
39 AirGate,
40 AirFlight,
41 BusCompany,
42 BusLine,
43 BusStop,
44 BusBerth,
45 BusConnection,
46 RailCompany,
47 RailLine,
48 RailStation,
49 RailPlatform,
50 RailConnection,
51 SeaCompany,
52 SeaLine,
53 SeaStop,
54 SeaDock,
55 SeaConnection,
56 SpawnWarp,
57 Town,
58}
59macro_rules! impl_any_node {
60 ($($Variant:ident),+) => {
61 impl AnyNode {
62 pub fn from_id(gd: &GD, id: ID) -> Result<Option<Self>> {
63 gd.0.query_one("SELECT type FROM Node WHERE i = ?", (id,), |row| {
64 Ok(match &*row.get::<_, String>(0)? {
65 $(stringify!($Variant) => $Variant(id).into(),)+
66 _ => unreachable!(),
67 })
68 }).optional().map_err(Into::into)
69 }
70 }
71 };
72}
73impl_any_node!(
74 AirAirline,
75 AirAirport,
76 AirGate,
77 AirFlight,
78 BusCompany,
79 BusLine,
80 BusStop,
81 BusBerth,
82 BusConnection,
83 RailCompany,
84 RailLine,
85 RailStation,
86 RailPlatform,
87 RailConnection,
88 SeaCompany,
89 SeaLine,
90 SeaStop,
91 SeaDock,
92 SeaConnection,
93 SpawnWarp,
94 Town
95);
96
97#[macro_export]
98macro_rules! node_type {
99 ($Ty:ident) => {
100 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
101 pub struct $Ty(pub(crate) ID);
102
103 impl $crate::node::Node for $Ty {
104 fn i(self) -> ID {
105 self.0
106 }
107 fn ty(self) -> &'static str {
108 stringify!($Ty)
109 }
110 }
111
112 impl From<ID> for $Ty {
113 fn from(value: ID) -> Self {
114 Self(value)
115 }
116 }
117
118 impl rusqlite::types::FromSql for $Ty {
119 fn column_result(
120 value: rusqlite::types::ValueRef<'_>,
121 ) -> rusqlite::types::FromSqlResult<Self> {
122 Ok(Self(ID::try_from(value.as_i64()?).map_err(|e| {
123 rusqlite::types::FromSqlError::Other(e.into())
124 })?))
125 }
126 }
127 };
128
129 (located $Ty:ident) => {
130 node_type!($Ty);
131
132 impl $crate::node::located::LocatedNode for $Ty {}
133 };
134}