railway-provider-search-ch-0.3.0/.cargo_vcs_info.json0000644000000001700000000000100161650ustar { "git": { "sha1": "db4730b96174cae902758d2659864d39e047a4d0" }, "path_in_vcs": "railway-provider-search-ch" }railway-provider-search-ch-0.3.0/Cargo.lock0000644000000643040000000000100141510ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "aho-corasick" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] name = "anstream" version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", "windows-sys 0.60.2", ] [[package]] name = "approx" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" dependencies = [ "num-traits", ] [[package]] name = "async-trait" version = "0.1.85" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" version = "1.2.49" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" dependencies = [ "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", "windows-link", ] [[package]] name = "chrono-tz" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" dependencies = [ "chrono", "phf", ] [[package]] name = "colorchoice" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "displaydoc" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "env_filter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" dependencies = [ "log", "regex", ] [[package]] name = "env_logger" version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ "anstream", "anstyle", "env_filter", "jiff", "log", ] [[package]] name = "find-msvc-tools" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "form_urlencoded" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] [[package]] name = "geo-types" version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bd1157f0f936bf0cd68dec91e8f7c311afe60295574d62b70d4861a1bfdf2d9" dependencies = [ "approx", "num-traits", "serde", ] [[package]] name = "geojson" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d728c1df1fbf328d74151efe6cb0586f79ee813346ea981add69bd22c9241b" dependencies = [ "geo-types", "log", "serde", "serde_json", "thiserror", ] [[package]] name = "iana-time-zone" version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "log", "wasm-bindgen", "windows-core", ] [[package]] name = "iana-time-zone-haiku" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ "cc", ] [[package]] name = "icu_collections" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locale_core" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_normalizer" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", "writeable", "yoke", "zerofrom", "zerotrie", "zerovec", ] [[package]] name = "idna" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", "utf8_iter", ] [[package]] name = "idna_adapter" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "is_terminal_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" dependencies = [ "jiff-static", "log", "portable-atomic", "portable-atomic-util", "serde_core", ] [[package]] name = "jiff-static" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "js-sys" version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] name = "libc" version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libm" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "litemap" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "log" version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", ] [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "percent-encoding" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "phf" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" dependencies = [ "phf_shared", ] [[package]] name = "phf_shared" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" dependencies = [ "siphasher", ] [[package]] name = "pin-project-lite" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "portable-atomic" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portable-atomic-util" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" dependencies = [ "portable-atomic", ] [[package]] name = "potential_utf" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] [[package]] name = "proc-macro2" version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] [[package]] name = "railway-core" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93677f9367e5a53020ecaf8822230201cc9cdf4f4772def98a39c663e4fd08c8" dependencies = [ "async-trait", "chrono", "chrono-tz", "geojson", "log", "url", ] [[package]] name = "railway-provider-search-ch" version = "0.3.0" dependencies = [ "async-trait", "chrono", "chrono-tz", "env_logger", "railway-core", "serde", "serde_json", "tokio", "url", ] [[package]] name = "regex" version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", ] [[package]] name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "siphasher" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "syn" version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "thiserror" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tinystr" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "tokio" version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ "pin-project-lite", "tokio-macros", ] [[package]] name = "tokio-macros" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "url" version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", ] [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wasm-bindgen" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ "unicode-ident", ] [[package]] name = "windows-core" version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", "windows-link", "windows-result", "windows-strings", ] [[package]] name = "windows-implement" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "windows-interface" version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] [[package]] name = "windows-targets" version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ "windows-link", "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "writeable" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "yoke" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerofrom" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerotrie" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", "zerofrom", ] [[package]] name = "zerovec" version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", "syn", ] railway-provider-search-ch-0.3.0/Cargo.toml0000644000000031270000000000100141700ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "railway-provider-search-ch" version = "0.3.0" authors = ["Julian Schmidhuber "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Implementation of the search.ch client for Railway" readme = "README.md" keywords = [ "railway-backend", "train", "public-transport", ] license = "AGPL-3.0-or-later OR EUPL-1.2" repository = "https://gitlab.com/schmiddi-on-mobile/railway-backend" [features] polylines = ["rcore/polylines"] rt-multi-thread = ["rcore/rt-multi-thread"] [lib] name = "railway_provider_search_ch" path = "src/lib.rs" [dependencies.async-trait] version = "0.1" [dependencies.chrono] version = "0.4" [dependencies.chrono-tz] version = "0.10.4" [dependencies.rcore] version = "0.3" package = "railway-core" [dependencies.serde] version = "1.0" features = ["derive"] [dependencies.serde_json] version = "1.0" [dependencies.url] version = "2.5.7" [dev-dependencies.env_logger] version = "0.11.8" [dev-dependencies.tokio] version = "1.48" features = [ "rt-multi-thread", "macros", ] railway-provider-search-ch-0.3.0/Cargo.toml.orig000064400000000000000000000020251046102023000176450ustar 00000000000000[package] name = "railway-provider-search-ch" version = "0.3.0" authors = ["Julian Schmidhuber "] edition = "2021" description = "Implementation of the search.ch client for Railway" repository = "https://gitlab.com/schmiddi-on-mobile/railway-backend" license = "AGPL-3.0-or-later OR EUPL-1.2" keywords = ["railway-backend", "train", "public-transport"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] rcore = { package = "railway-core", path = "../railway-core", version = "0.3" } serde = { version = "1.0", features = [ "derive" ] } serde_json = "1.0" chrono = { version = "0.4" } chrono-tz = "0.10.4" url = "2.5.7" async-trait = "0.1" [features] rt-multi-thread = [ "rcore/rt-multi-thread" ] polylines = [ "rcore/polylines" ] [dev-dependencies] tokio = { version = "1.48", features = [ "rt-multi-thread", "macros" ] } env_logger = "0.11.8" rcore = { package = "railway-core", path = "../railway-core", features = [ "reqwest-requester" ] } railway-provider-search-ch-0.3.0/README.md000064400000000000000000000006271046102023000162430ustar 00000000000000# Railway search.ch Provider Implementation of the search.ch client for Railway. This crate is part of [railway-backend](https://gitlab.com/schmiddi-on-mobile/railway-backend). You can find a high-level documentation of railway-backend [here](https://gitlab.com/schmiddi-on-mobile/railway-backend/-/tree/main/docs?ref_type=heads). Documentation can be found [here](https://search.ch/timetable/api/help). railway-provider-search-ch-0.3.0/src/error.rs000064400000000000000000000007011046102023000172430ustar 00000000000000use std::fmt::Display; #[derive(Debug)] pub enum Error { Json(serde_json::Error), RefreshJourneyNotFound, } impl Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match &self { Self::Json(e) => write!(f, "json error: {}", e), Self::RefreshJourneyNotFound => write!(f, "refresh journey not found"), } } } impl std::error::Error for Error {} railway-provider-search-ch-0.3.0/src/lib.rs000064400000000000000000000221561046102023000166700ustar 00000000000000#![doc = include_str!("../README.md")] mod error; mod serialize; mod types; use error::Error; use types::*; use async_trait::async_trait; use rcore::{ Journey, JourneysOptions, Location, Mode, ProductsSelection, Provider, Requester, RequesterBuilder, }; use url::Url; use std::collections::{HashMap, HashSet}; pub const API_URL: &str = "https://search.ch/timetable/api"; #[derive(Clone)] pub struct SearchChClient { requester: R, url: Url, } impl SearchChClient { pub fn new>(requester: RB) -> Self { Self { requester: requester.build(), url: Url::parse(API_URL).expect("Failed to parse API_URL"), } } } fn products_to_api_type(selection: ProductsSelection) -> String { HashSet::::from(selection) .into_iter() .flat_map(mode_to_api_type) .fold(String::new(), |acc, m| format!("{},{}", acc, m)) } fn mode_to_api_type(mode: Mode) -> Option<&'static str> { match mode { Mode::HighSpeedTrain => Some("train"), Mode::RegionalTrain => Some("train"), Mode::SuburbanTrain => Some("train"), Mode::Subway => Some("tram"), Mode::Tram => Some("tram"), Mode::Bus => Some("bus"), Mode::Ferry => Some("ship"), Mode::Cablecar => Some("cableway"), Mode::OnDemand => None, Mode::Unknown => None, } } #[cfg_attr(feature = "rt-multi-thread", async_trait)] #[cfg_attr(not(feature = "rt-multi-thread"), async_trait(?Send))] impl Provider for SearchChClient { type Error = Error; async fn journeys( &self, from: rcore::Place, to: rcore::Place, opts: rcore::JourneysOptions, ) -> Result::Error, Self::Error>> { let place_to_id = |p| match p { rcore::Place::Station(s) => s.id, rcore::Place::Location(Location::Address { address, .. }) => address, // TODO: Error when not set rcore::Place::Location(Location::Point { id, name, .. }) => { id.or(name).unwrap_or_default() } }; let time = opts .earlier_than .as_ref() .and_then(|t| chrono::DateTime::parse_from_rfc3339(t).ok()) .or_else(|| { opts.later_than .as_ref() .and_then(|t| chrono::DateTime::parse_from_rfc3339(t).ok()) }) .or_else(|| opts.departure.as_ref().map(|t| t.fixed_offset())) .or_else(|| opts.arrival.as_ref().map(|t| t.fixed_offset())) .map(|t| t.with_timezone(&chrono_tz::Europe::Zurich)); let time_type = if opts.arrival.is_some() { "arrival" } else { "depart" }; let num = if opts.earlier_than.is_some() { 0 } else { opts.results }; let pre = if opts.earlier_than.is_some() { opts.results } else { 0 }; let transport_types = products_to_api_type(opts.products); let mut url = self.url.clone(); url.path_segments_mut() .expect("API URL cannot-be-a-base") .push("route.json"); url.query_pairs_mut() .append_pair("from", &place_to_id(from)) .append_pair("to", &place_to_id(to)) .append_pair("show_delays", "1") .append_pair("show_trackchanges", "1") .append_pair( "date", &time .as_ref() .map(|t| t.format("%d.%m.%Y").to_string()) .unwrap_or_else(|| "today".to_owned()), ) .append_pair( "time", &time .as_ref() .map(|t| t.format("%H:%M").to_string()) .unwrap_or_else(|| "now".to_owned()), ) .append_pair("time_type", time_type) .append_pair("num", &num.to_string()) .append_pair("pre", &pre.to_string()) .append_pair("transportation_types", &transport_types); let response = self .requester .get(&url, &[], HashMap::new()) .await .map_err(rcore::Error::Request)?; let response: SearchChJourneysResponse = serde_json::from_slice(&response) .map_err(|e| rcore::Error::Provider(Error::Json(e)))?; Ok(response.into()) } /// Note: search.ch does not support setting the search language or the number of results async fn locations( &self, opts: rcore::LocationsOptions, ) -> Result::Error, Self::Error>> { let mut url = self.url.clone(); url.path_segments_mut() .expect("API URL cannot-be-a-base") .push("completion.json"); url.query_pairs_mut() .append_pair("term", &opts.query) .append_pair("show_ids", "1") .append_pair("show_coordinates", "1"); let response = self .requester .get(&url, &[], HashMap::new()) .await .map_err(rcore::Error::Request)?; let response: SearchChLocationsResponse = serde_json::from_slice(&response) .map_err(|e| rcore::Error::Provider(Error::Json(e)))?; Ok(response.into_iter().map(Into::into).collect()) } async fn station_board( &self, _place: rcore::Place, _kind: rcore::StationBoardKind, _opts: rcore::StationBoardOptions, ) -> Result::Error, Self::Error>> { Err(rcore::Error::NotImplemented) } // Note: search.ch does not support any of those options. // This method is not guaranteed to find the same journey. But I think this is the best we can do as search.ch does not provide a refresh-API. async fn refresh_journey( &self, journey: &Journey, _opts: rcore::RefreshJourneyOptions, ) -> Result::Error, Self::Error>> { // Note: Each journey should have at least one leg. let from = &journey.legs[0].origin; let to = &journey.legs[journey.legs.len() - 1].destination; let jopts = JourneysOptions { // In most cases, the journey to refresh is likely the first one. Relax this requirement a bit. results: 3, departure: journey.legs[0].planned_departure, ..Default::default() }; self.journeys(from.clone(), to.clone(), jopts) .await? .journeys .into_iter() .find(|j| j.id == journey.id) .clone() .ok_or(rcore::Error::Provider(Error::RefreshJourneyNotFound)) } } #[cfg(test)] mod test { use rcore::{ JourneysOptions, Location, LocationsOptions, Place, ReqwestRequesterBuilder, Station, }; use super::*; pub async fn check_search>( search: S, expected: S, ) -> Result<(), Box> { let client = SearchChClient::new(ReqwestRequesterBuilder::default()); let locations = client .locations(LocationsOptions { query: search.as_ref().to_string(), ..Default::default() }) .await?; let results = locations .into_iter() .flat_map(|p| match p { Place::Station(s) => s.name, Place::Location(Location::Address { address, .. }) => Some(address), Place::Location(Location::Point { name, .. }) => name, }) .collect::>(); assert!( results.iter().find(|s| s == &expected.as_ref()).is_some(), "expected {} to be contained in {:#?}", expected.as_ref(), results ); Ok(()) } pub async fn check_journey>( from: S, to: S, ) -> Result<(), Box> { let client = SearchChClient::new(ReqwestRequesterBuilder::default()); let journeys = client .journeys( Place::Station(Station { id: from.as_ref().to_string(), ..Default::default() }), Place::Station(Station { id: to.as_ref().to_string(), ..Default::default() }), JourneysOptions::default(), ) .await?; assert!( !journeys.journeys.is_empty(), "expected journey from {} to {} to exist", from.as_ref(), to.as_ref() ); Ok(()) } #[tokio::test] async fn search_luzern() -> Result<(), Box> { check_search("Lu", "Luzern").await } #[tokio::test] async fn journey_winterthur_lausanne() -> Result<(), Box> { check_journey("8506000", "8501120").await } } railway-provider-search-ch-0.3.0/src/serialize.rs000064400000000000000000000032021046102023000201000ustar 00000000000000// From . pub(crate) mod time { use chrono::NaiveDateTime; use serde::{self, Deserialize, Deserializer, Serializer}; const FORMAT: &str = "%Y-%m-%d %H:%M:%S"; pub fn serialize(date: &NaiveDateTime, serializer: S) -> Result where S: Serializer, { let s = format!("{}", date.format(FORMAT)); serializer.serialize_str(&s) } pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; let dt = NaiveDateTime::parse_from_str(&s, FORMAT).map_err(serde::de::Error::custom)?; Ok(dt) } } pub(crate) mod optional_time { use chrono::NaiveDateTime; use serde::{self, Deserialize, Deserializer, Serializer}; const FORMAT: &str = "%Y-%m-%d %H:%M:%S"; pub fn serialize(date: &Option, serializer: S) -> Result where S: Serializer, { if let Some(date) = date { let s = format!("{}", date.format(FORMAT)); serializer.serialize_str(&s) } else { serializer.serialize_none() } } pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { let s: Option = Option::deserialize(deserializer)?; if let Some(s) = s { let dt = NaiveDateTime::parse_from_str(&s, FORMAT).map_err(serde::de::Error::custom)?; Ok(Some(dt)) } else { Ok(None) } } } railway-provider-search-ch-0.3.0/src/types.rs000064400000000000000000000361471046102023000172730ustar 00000000000000use crate::serialize; use rcore::{ IntermediateLocation, Journey, JourneysResponse, Leg, Line, Location, Mode, Operator, Place, Product, Remark, Station, Stop, }; use chrono::{DateTime, Duration, NaiveDateTime}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; fn convert_datetime(t: NaiveDateTime) -> Option> { // Note: Should in theory never return `None` as the returned time is in Europe/Zurich time. // This time could be ambiguous though (when switching between summer/winter time), not sure what we can do there as the API does not specify which is the correct one. t.and_local_timezone(chrono_tz::Europe::Zurich).earliest() } fn convert_datetime_with_delay>( t: NaiveDateTime, d: Option, ) -> Option> { let time = convert_datetime(t)?; if let Some(d) = d { let d = d.as_ref(); let delay = d .parse::() .map(Duration::minutes) .unwrap_or_else(|_| Duration::zero()); Some(time + delay) } else { Some(time) } } fn type_string_to_mode>(s: S) -> Mode { match s.as_ref() { "strain" => Mode::SuburbanTrain, "walk" => Mode::Unknown, "tram" => Mode::Tram, "express_train" => Mode::HighSpeedTrain, "bus" => Mode::Bus, // TODO _ => Mode::Unknown, } } pub type SearchChLocationsResponse = Vec; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SearchChLocationsResponseItem { label: String, id: Option, lon: Option, lat: Option, } impl From for Place { fn from(item: SearchChLocationsResponseItem) -> Place { if let Some(id) = item.id { Place::Station(Station { id: id.clone(), name: Some(item.label.clone()), location: Some(Location::Point { id: Some(id), name: Some(item.label), poi: None, latitude: item.lat.unwrap_or_default(), longitude: item.lon.unwrap_or_default(), }), products: vec![], }) } else { // Lat/Lon not given. Place::Location(Location::Address { address: item.label, latitude: item.lat.unwrap_or_default(), longitude: item.lon.unwrap_or_default(), }) } } } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SearchChJourneysResponse { connections: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SearchChConnection { from: String, #[serde(with = "serialize::time")] departure: chrono::NaiveDateTime, dep_delay: Option, to: String, #[serde(with = "serialize::time")] arrival: chrono::NaiveDateTime, arr_delay: Option, // Note: Sometimes int, sometimes float duration: f64, // is_main, disruptions legs: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SearchChLeg { #[serde(default)] #[serde(with = "serialize::optional_time")] departure: Option, tripid: Option, stopid: String, // x, y name: String, // sbb_name, terminal, fgcolor, bgcolor r#type: Option, line: Option, #[serde(rename = "*G")] star_g: Option, #[serde(rename = "*L")] star_l: Option, operator: Option, stops: Option>, // contop_stop, runningtime exit: Option, // occupancy dep_delay: Option, track: Option, type_name: Option, lon: f32, lat: f32, cancelled: Option, // Note: This either is a map or an empty vec. disruptions: Option, // TODO: Attributes } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(untagged)] pub enum SearchChDisruptions { Map(HashMap), Vec(Vec), } impl From for Vec { fn from(disruptions: SearchChDisruptions) -> Self { match disruptions { SearchChDisruptions::Map(m) => m.into_values().map(Into::into).collect(), SearchChDisruptions::Vec(v) => v.into_iter().map(Into::into).collect(), } } } impl Default for SearchChDisruptions { fn default() -> Self { Self::Vec(Vec::new()) } } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SearchChDisruption { id: String, texts: SearchChDisruptionTexts, // A lot more fields which are not too interesting. } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SearchChDisruptionTexts { // Also has M and L which seem to be mostly the same to S. Not sure what is the difference. // public-transport-enabler seems to only use S: #[serde(rename = "S")] s: SearchChDisruptionText, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SearchChDisruptionText { summary: Option, reason: Option, duration: Option, consequence: Option, recommendation: Option, } impl From for Remark { fn from(disruption: SearchChDisruption) -> Remark { let texts = disruption.texts.s; Remark { code: disruption.id, text: vec![ texts.summary.clone(), texts.reason, texts.duration, texts.consequence, texts.recommendation, ] .into_iter() .flatten() .map(|t| t + ".") .collect::>() .join(" "), r#type: rcore::RemarkType::Status, association: rcore::RemarkAssociation::None, summary: texts.summary, trip_id: None, } } } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SearchChStop { #[serde(default)] #[serde(with = "serialize::optional_time")] arrival: Option, arr_delay: Option, #[serde(default)] #[serde(with = "serialize::optional_time")] departure: Option, dep_delay: Option, name: String, stopid: String, // x, y, lon: f32, lat: f32, } impl From for IntermediateLocation { fn from(stop: SearchChStop) -> IntermediateLocation { if stop.departure.is_some() { Self::Stop(Stop { place: Place::Station(Station { id: stop.stopid.clone(), name: Some(stop.name.clone()), location: Some(Location::Point { id: Some(stop.stopid), name: Some(stop.name), poi: None, latitude: stop.lat, longitude: stop.lon, }), products: vec![], }), departure: stop .departure .and_then(|d| convert_datetime_with_delay(d, stop.dep_delay.as_ref())), planned_departure: stop.departure.and_then(convert_datetime), arrival: stop .arrival .and_then(|d| convert_datetime_with_delay(d, stop.arr_delay.as_ref())), planned_arrival: stop.arrival.and_then(convert_datetime), // Note: The API does not provide track information for stopovers. arrival_platform: None, planned_arrival_platform: None, departure_platform: None, planned_departure_platform: None, // Note: The API does not provide cancellation or remark information for stopovers. cancelled: false, remarks: vec![], }) } else { Self::Railway(Place::Location(Location::Point { id: Some(stop.stopid), name: Some(stop.name), poi: None, latitude: stop.lat, longitude: stop.lon, })) } } } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SearchChExit { #[serde(with = "serialize::time")] arrival: chrono::NaiveDateTime, stopid: String, // x, y name: String, // sbb_name, waittime, track: Option, arr_delay: Option, lon: f32, lat: f32, } impl From for JourneysResponse { fn from(response: SearchChJourneysResponse) -> JourneysResponse { Self { earlier_ref: response .connections .first() .and_then(|c| convert_datetime(c.departure)) .map(|t| t.to_rfc3339()), later_ref: response .connections .last() .and_then(|c| convert_datetime(c.departure)) .map(|t| t.to_rfc3339()), journeys: response.connections.into_iter().map(Into::into).collect(), } } } impl From for Journey { fn from(connection: SearchChConnection) -> Self { let mut legs: Vec = connection.legs.into_iter().map(Into::into).collect(); // Note: Last "leg" is always destination. legs.remove(legs.len() - 1); Self { id: legs .iter() .flat_map(|l| l.trip_id.as_ref()) .map(|s| &s[..]) .collect(), legs, price: None, } } } impl From for Leg { fn from(leg: SearchChLeg) -> Leg { let origin = Place::Station(Station { id: leg.stopid.clone(), name: Some(leg.name.clone()), location: Some(Location::Point { id: Some(leg.stopid), name: Some(leg.name), poi: None, latitude: leg.lat, longitude: leg.lon, }), products: vec![], }); let destination = Place::Station(Station { id: leg .exit .as_ref() .map(|e| e.stopid.clone()) .unwrap_or_default(), name: leg.exit.as_ref().map(|e| e.name.clone()), location: Some(Location::Point { id: leg.exit.as_ref().map(|e| e.stopid.clone()), name: leg.exit.as_ref().map(|e| e.name.clone()), poi: None, latitude: leg.exit.as_ref().map(|e| e.lat).unwrap_or_default(), longitude: leg.exit.as_ref().map(|e| e.lon).unwrap_or_default(), }), products: vec![], }); let planned_departure = leg.departure.and_then(convert_datetime); let planned_arrival = leg.exit.as_ref().and_then(|e| convert_datetime(e.arrival)); let departure = leg .departure .and_then(|d| convert_datetime_with_delay(d, leg.dep_delay.as_ref())); let arrival = leg .exit .as_ref() .and_then(|e| convert_datetime_with_delay(e.arrival, e.arr_delay.as_ref())); let arrival_platform = leg.exit.as_ref().and_then(|e| e.track.clone()); let departure_platform = leg.track.clone(); let r#type = leg.r#type.unwrap_or_default(); let mode = type_string_to_mode(&r#type); let mut intermediate_locations = vec![IntermediateLocation::Stop(Stop { place: origin.clone(), departure, planned_departure, arrival: None, planned_arrival: None, arrival_platform: None, planned_arrival_platform: None, // TODO: Track changes // When tracks change, the API does not return which was the old track but only the new one with an exclamation-mark. departure_platform: departure_platform.clone(), planned_departure_platform: departure_platform.clone(), cancelled: false, remarks: vec![], })]; // Note: Should we consider filtering out "Bahn-2000-Strecke" and others. This is no real stopover. // Or should we change semantics of a "stopover" to also include that? // See also and . intermediate_locations.extend(leg.stops.unwrap_or_default().into_iter().map(Into::into)); intermediate_locations.push(IntermediateLocation::Stop(Stop { place: destination.clone(), departure: None, planned_departure: None, arrival, planned_arrival, // TODO: Track changes // When tracks change, the API does not return which was the old track but only the new one with an exclamation-mark. arrival_platform: arrival_platform.clone(), planned_arrival_platform: arrival_platform.clone(), departure_platform: None, planned_departure_platform: None, cancelled: false, remarks: vec![], })); Leg { origin, destination, departure, planned_departure, arrival, planned_arrival, reachable: true, trip_id: leg.tripid, line: if r#type != "walk" { Some(Line { name: leg.line.clone(), fahrt_nr: leg.star_l, mode: mode.clone(), product: Product { mode, name: leg.star_g.clone().unwrap_or_default().into(), short: leg.star_g.clone().unwrap_or_default().into(), }, operator: leg.operator.map(|o| Operator { id: o.clone(), name: o.clone(), }), product_name: leg.star_g, }) } else { None }, direction: None, // TODO: Track changes // When tracks change, the API does not return which was the old track but only the new one with an exclamation-mark. arrival_platform: arrival_platform.clone(), planned_arrival_platform: arrival_platform, departure_platform: departure_platform.clone(), planned_departure_platform: departure_platform, intermediate_locations, #[cfg(feature = "polylines")] polyline: None, walking: r#type == "walk", cancelled: leg.cancelled.unwrap_or_default(), remarks: leg.disruptions.unwrap_or_default().into(), // Information not provided. load_factor: None, transfer: false, distance: None, frequency: None, } } }