From 04bdb41dbf34e64b17dbd924c598644fa2b6084c Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Wed, 5 Feb 2025 01:49:44 -0500 Subject: [PATCH] Implement most setters as a Rust struct --- include/mbgl/util/tile_server_options.hpp | 2 +- platform/rust/include/wrapper.h | 47 ++ platform/rust/src/lib.rs | 414 +++-------------- platform/rust/src/tile_server_options.rs | 536 ++++++++++++++++++++++ 4 files changed, 640 insertions(+), 359 deletions(-) create mode 100644 platform/rust/src/tile_server_options.rs diff --git a/include/mbgl/util/tile_server_options.hpp b/include/mbgl/util/tile_server_options.hpp index 8fc1b943f6a..2182f34d9f2 100644 --- a/include/mbgl/util/tile_server_options.hpp +++ b/include/mbgl/util/tile_server_options.hpp @@ -265,7 +265,7 @@ class TileServerOptions final { TileServerOptions& withDefaultStyles(std::vector styles); /** - * @brief Sets the default style by name. The style name must exists in + * @brief Sets the default style by name. The style name must exist in * defaultStyles collection * * @param defaultStyle The style name diff --git a/platform/rust/include/wrapper.h b/platform/rust/include/wrapper.h index 3502a054b6e..7825ca85850 100644 --- a/platform/rust/include/wrapper.h +++ b/platform/rust/include/wrapper.h @@ -44,5 +44,52 @@ inline const int8_t* TileServerOptions_tileVersionPrefix(const TileServerOptions return get_raw_str_ptr(self.tileVersionPrefix()); } +// TileServerOptions setters +inline void TileServerOptions_withBaseURL(TileServerOptions& self, const rust::Str value) { + self.withBaseURL((std::string)value); +} +inline void TileServerOptions_withUriSchemeAlias(TileServerOptions& self, const rust::Str value) { + self.withUriSchemeAlias((std::string)value); +} +inline void TileServerOptions_withSourceTemplate(TileServerOptions& self, const rust::Str source_template, const rust::Str domain_name, const int8_t* version_prefix) { + self.withSourceTemplate( + (std::string)source_template, + (std::string)domain_name, + (version_prefix ? std::string((const char*)version_prefix) : std::optional{})); +} +inline void TileServerOptions_withStyleTemplate(TileServerOptions& self, const rust::Str style_template, const rust::Str domain_name, const int8_t* version_prefix) { + self.withStyleTemplate( + (std::string)style_template, + (std::string)domain_name, + (version_prefix ? std::string((const char*)version_prefix) : std::optional{})); +} +inline void TileServerOptions_withSpritesTemplate(TileServerOptions& self, const rust::Str sprites_template, const rust::Str domain_name, const int8_t* version_prefix) { + self.withSpritesTemplate( + (std::string)sprites_template, + (std::string)domain_name, + (version_prefix ? std::string((const char*)version_prefix) : std::optional{})); +} +inline void TileServerOptions_withGlyphsTemplate(TileServerOptions& self, const rust::Str glyphs_template, const rust::Str domain_name, const int8_t* version_prefix) { + self.withGlyphsTemplate( + (std::string)glyphs_template, + (std::string)domain_name, + (version_prefix ? std::string((const char*)version_prefix) : std::optional{})); +} +inline void TileServerOptions_withTileTemplate(TileServerOptions& self, const rust::Str tile_template, const rust::Str domain_name, const int8_t* version_prefix) { + self.withTileTemplate( + (std::string)tile_template, + (std::string)domain_name, + (version_prefix ? std::string((const char*)version_prefix) : std::optional{})); +} +inline void TileServerOptions_withApiKeyParameterName(TileServerOptions& self, const rust::Str value) { + self.withApiKeyParameterName((std::string)value); +} +inline void TileServerOptions_setRequiresApiKey(TileServerOptions& self, bool value) { + self.setRequiresApiKey(value); +} +inline void TileServerOptions_withDefaultStyle(TileServerOptions& self, const rust::Str value) { + self.withDefaultStyle((std::string)value); +} + } // namespace bridge } // namespace ml diff --git a/platform/rust/src/lib.rs b/platform/rust/src/lib.rs index a8a987d2df9..73e25f29a72 100644 --- a/platform/rust/src/lib.rs +++ b/platform/rust/src/lib.rs @@ -1,8 +1,5 @@ -use std::ffi::{c_char, CStr}; -use std::fmt; -use std::fmt::Debug; - -use cxx::UniquePtr; +mod tile_server_options; +pub use tile_server_options::TileServerOptions; #[cxx::bridge(namespace = "ml::bridge")] mod ffi { @@ -10,378 +7,79 @@ mod ffi { unsafe extern "C++" { include!("maplibre-native/include/wrapper.h"); - // We specify the C++ namespace and the free function name exactly. - // cxx can bind free functions directly if they have a compatible signature. - // The signature must match what's in log2.hpp: - // "uint32_t ceil_log2(uint64_t x);" - // - // We'll express that to Rust as (u64 -> u32). - #[namespace = "mbgl::util"] - pub fn ceil_log2(x: u64) -> u32; - - // A function defined in the C++ Rust wrapper rather than the core lib. - pub fn get_42() -> u32; - #[namespace = "mbgl"] type TileServerOptions; - /// Create a new default configuration fn TileServerOptions_new() -> UniquePtr; - /// Get the tile server options configured for MapLibre. fn TileServerOptions_mapbox() -> UniquePtr; - /// Get the tile server options configured for Mapbox. fn TileServerOptions_maplibre() -> UniquePtr; - /// Get the tile server options configured for MapTiler. fn TileServerOptions_maptiler() -> UniquePtr; - // /// Sets the API base URL. - // #[cxx_name = "withBaseURL"] - // TileServerOptions& withBaseURL(std::string baseURL); - - /// Gets the base URL. - #[cxx_name = "baseURL"] - fn base_url(self: &TileServerOptions) -> &CxxString; - - // /// Sets the scheme alias for the tile server. For example maptiler:// for MapTiler. - // #[cxx_name = "withUriSchemeAlias"] - // TileServerOptions& withUriSchemeAlias(std::string alias); - - /// Gets the URI scheme alias. - #[cxx_name = "uriSchemeAlias"] - fn uri_scheme_alias(self: &TileServerOptions) -> &CxxString; - - // /// Sets the template for sources. - // #[cxx_name = "withSourceTemplate"] - // TileServerOptions& withSourceTemplate(std::string sourceTemplate, std::string domainName, std::optional versionPrefix); - - /// Gets the source template. - #[cxx_name = "sourceTemplate"] - fn source_template(self: &TileServerOptions) -> &CxxString; - - /// Gets the source domain name. - #[cxx_name = "sourceDomainName"] - fn source_domain_name(self: &TileServerOptions) -> &CxxString; - - /// Gets the source version prefix. + fn TileServerOptions_withBaseURL(obj: Pin<&mut TileServerOptions>, value: &str); + fn baseURL(self: &TileServerOptions) -> &CxxString; + fn TileServerOptions_withUriSchemeAlias(obj: Pin<&mut TileServerOptions>, value: &str); + fn uriSchemeAlias(self: &TileServerOptions) -> &CxxString; + unsafe fn TileServerOptions_withSourceTemplate( + obj: Pin<&mut TileServerOptions>, + source_template: &str, + domain_name: &str, + version_prefix: *const i8, + ); + fn sourceTemplate(self: &TileServerOptions) -> &CxxString; + fn sourceDomainName(self: &TileServerOptions) -> &CxxString; unsafe fn TileServerOptions_sourceVersionPrefix(value: &TileServerOptions) -> *const i8; - - // /// Sets the template for styles. If `domainName` is set, the URL domain must contain the specified - // /// string to be matched as canonical style URL. - // #[cxx_name = "withStyleTemplate"] - // TileServerOptions& withStyleTemplate(std::string styleTemplate, std::string domainName, std::optional versionPrefix); - - /// Gets the style template. - #[cxx_name = "styleTemplate"] - fn style_template(self: &TileServerOptions) -> &CxxString; - - /// Gets the style domain name. - #[cxx_name = "styleDomainName"] - fn style_domain_name(self: &TileServerOptions) -> &CxxString; - - /// Gets the style version prefix. + unsafe fn TileServerOptions_withStyleTemplate( + obj: Pin<&mut TileServerOptions>, + style_template: &str, + domain_name: &str, + version_prefix: *const i8, + ); + fn styleTemplate(self: &TileServerOptions) -> &CxxString; + fn styleDomainName(self: &TileServerOptions) -> &CxxString; unsafe fn TileServerOptions_styleVersionPrefix(value: &TileServerOptions) -> *const i8; - // fn style_version_prefix(self: &TileServerOptions) -> &CxxString; - - // /// Sets the template for sprites. - // /// If `domainName` is set, the URL domain must contain the specified - // /// string to be matched as canonical sprite URL. - // #[cxx_name = "withSpritesTemplate"] - // TileServerOptions& withSpritesTemplate(std::string spritesTemplate, std::string domainName, std::optional versionPrefix); - - /// Gets the sprites template. - #[cxx_name = "spritesTemplate"] - fn sprites_template(self: &TileServerOptions) -> &CxxString; - - /// Gets the sprites domain name. - #[cxx_name = "spritesDomainName"] - fn sprites_domain_name(self: &TileServerOptions) -> &CxxString; - - /// Gets the sprites version prefix. + unsafe fn TileServerOptions_withSpritesTemplate( + obj: Pin<&mut TileServerOptions>, + sprites_template: &str, + domain_name: &str, + version_prefix: *const i8, + ); + fn spritesTemplate(self: &TileServerOptions) -> &CxxString; + fn spritesDomainName(self: &TileServerOptions) -> &CxxString; unsafe fn TileServerOptions_spritesVersionPrefix(value: &TileServerOptions) -> *const i8; - // fn sprites_version_prefix(self: &TileServerOptions) -> *const CxxString; - - // /// Sets the template for glyphs. - // /// If set, the URL domain must contain the specified - // /// string to be matched as canonical glyphs URL. - // #[cxx_name = "withGlyphsTemplate"] - // TileServerOptions& withGlyphsTemplate(std::string glyphsTemplate, std::string domainName, std::optional versionPrefix); - - /// Gets the glyphs template. - #[cxx_name = "glyphsTemplate"] - fn glyphs_template(self: &TileServerOptions) -> &CxxString; - - /// Gets the glyphs domain name. - #[cxx_name = "glyphsDomainName"] - fn glyphs_domain_name(self: &TileServerOptions) -> &CxxString; - - /// Gets the glyphs version prefix. + unsafe fn TileServerOptions_withGlyphsTemplate( + obj: Pin<&mut TileServerOptions>, + glyphs_template: &str, + domain_name: &str, + version_prefix: *const i8, + ); + fn glyphsTemplate(self: &TileServerOptions) -> &CxxString; + fn glyphsDomainName(self: &TileServerOptions) -> &CxxString; unsafe fn TileServerOptions_glyphsVersionPrefix(value: &TileServerOptions) -> *const i8; - // fn glyphs_version_prefix(self: &TileServerOptions) -> &CxxString; - - // /// Sets the template for tiles. - // /// - // /// If `domainName` is set, the URL domain must contain the specified - // /// string to be matched as canonical tile URL. - // #[cxx_name = "withTileTemplate"] - // TileServerOptions& withTileTemplate(std::string tileTemplate, std::string domainName, std::optional versionPrefix); - - /// Gets the tile template. - #[cxx_name = "tileTemplate"] - fn tile_template(self: &TileServerOptions) -> &CxxString; - - /// Gets the tile domain name. - #[cxx_name = "tileDomainName"] - fn tile_domain_name(self: &TileServerOptions) -> &CxxString; - - /// Gets the tile version prefix. + unsafe fn TileServerOptions_withTileTemplate( + obj: Pin<&mut TileServerOptions>, + tile_template: &str, + domain_name: &str, + version_prefix: *const i8, + ); + fn tileTemplate(self: &TileServerOptions) -> &CxxString; + fn tileDomainName(self: &TileServerOptions) -> &CxxString; unsafe fn TileServerOptions_tileVersionPrefix(value: &TileServerOptions) -> *const i8; - // fn tile_version_prefix(self: &TileServerOptions) -> &CxxString; - - // /// Sets the access token parameter name. - // #[cxx_name = "withApiKeyParameterName"] - // TileServerOptions& withApiKeyParameterName(std::string apiKeyParameterName); - - /// Gets the API key parameter name. - #[cxx_name = "apiKeyParameterName"] - fn api_key_parameter_name(self: &TileServerOptions) -> &CxxString; - - // #[cxx_name = "setRequiresApiKey"] - // TileServerOptions& setRequiresApiKey(bool apiKeyRequired); - - /// Checks if an API key is required. - #[cxx_name = "requiresApiKey"] - fn requires_api_key(self: &TileServerOptions) -> bool; + unsafe fn TileServerOptions_withApiKeyParameterName( + obj: Pin<&mut TileServerOptions>, + value: &str, + ); + fn apiKeyParameterName(self: &TileServerOptions) -> &CxxString; + fn TileServerOptions_setRequiresApiKey(obj: Pin<&mut TileServerOptions>, value: bool); + fn requiresApiKey(self: &TileServerOptions) -> bool; // /// Gets the default styles. - // #[cxx_name = "defaultStyles"] // const std::vector defaultStyles() const; // /// Sets the collection default styles. - // #[cxx_name = "withDefaultStyles"] // TileServerOptions& withDefaultStyles(std::vector styles); - // #[cxx_name = "withDefaultStyle"] - // fn set_default_style(self: &TileServerOptions); - - /// Gets the default style. - #[cxx_name = "defaultStyle"] - fn default_style(self: &TileServerOptions) -> &CxxString; - } -} - -// Re-export native functions that do not need safety wrappers. -pub use ffi::{ceil_log2, get_42, TileServerOptions}; - -// Add more methods to make usage more ergonomic -impl TileServerOptions { - /// Convert a pointer to a C string to an optional Rust &CStr with lifetime of &self. - /// - /// # Safety - /// The &CStr will remain valid as long as the TileServerOptions `&self` remains valid. - /// If some code tries to modify self, it will need to use &mut self, - /// which will not compile unless there are no &CStr references, as they use the same lifetime. - unsafe fn to_opt(&self, value: *const c_char) -> Option<&CStr> { - value.as_ref().map(|v| CStr::from_ptr(v)) - } - - /// Create a new default configuration - pub fn new() -> UniquePtr { - ffi::TileServerOptions_new() - } - - /// Get the tile server options configured for MapLibre. - pub fn default_mapbox() -> UniquePtr { - ffi::TileServerOptions_mapbox() - } - - /// Get the tile server options configured for Mapbox. - pub fn default_maplibre() -> UniquePtr { - ffi::TileServerOptions_maplibre() - } - - /// Get the tile server options configured for MapTiler. - pub fn default_maptiler() -> UniquePtr { - ffi::TileServerOptions_maptiler() - } - - /// Gets the source version prefix. - pub fn source_version_prefix(&self) -> Option<&CStr> { - unsafe { self.to_opt(ffi::TileServerOptions_sourceVersionPrefix(self)) } - } - - /// Gets the style version prefix. - pub fn style_version_prefix(&self) -> Option<&CStr> { - unsafe { self.to_opt(ffi::TileServerOptions_styleVersionPrefix(self)) } - } - - /// Gets the sprites version prefix. - pub fn sprites_version_prefix(&self) -> Option<&CStr> { - unsafe { self.to_opt(ffi::TileServerOptions_spritesVersionPrefix(self)) } - } - - /// Gets the glyphs version prefix. - pub fn glyphs_version_prefix(&self) -> Option<&CStr> { - unsafe { self.to_opt(ffi::TileServerOptions_glyphsVersionPrefix(self)) } - } - - /// Gets the tile version prefix. - pub fn tile_version_prefix(&self) -> Option<&CStr> { - unsafe { self.to_opt(ffi::TileServerOptions_tileVersionPrefix(self)) } - } -} - -impl Debug for TileServerOptions { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TileServerOptions") - .field("base_url", &self.base_url()) - .field("uri_scheme_alias", &self.uri_scheme_alias()) - .field("source_template", &self.source_template()) - .field("source_domain_name", &self.source_domain_name()) - .field("source_version_prefix", &self.source_version_prefix()) - .field("style_template", &self.style_template()) - .field("style_domain_name", &self.style_domain_name()) - .field("style_version_prefix", &self.style_version_prefix()) - .field("sprites_template", &self.sprites_template()) - .field("sprites_domain_name", &self.sprites_domain_name()) - .field("sprites_version_prefix", &self.sprites_version_prefix()) - .field("glyphs_template", &self.glyphs_template()) - .field("glyphs_domain_name", &self.glyphs_domain_name()) - .field("glyphs_version_prefix", &self.glyphs_version_prefix()) - .field("tile_template", &self.tile_template()) - .field("tile_domain_name", &self.tile_domain_name()) - .field("tile_version_prefix", &self.tile_version_prefix()) - .field("api_key_parameter_name", &self.api_key_parameter_name()) - .field("requires_api_key", &self.requires_api_key()) - .field("default_style", &self.default_style()) - .finish() - } -} - -#[cfg(test)] -mod tests { - use insta::assert_debug_snapshot; - - use super::*; - - #[test] - fn test_defaults() { - assert_debug_snapshot!(TileServerOptions::new(), @r#" - TileServerOptions { - base_url: "", - uri_scheme_alias: "", - source_template: "", - source_domain_name: "", - source_version_prefix: None, - style_template: "", - style_domain_name: "", - style_version_prefix: None, - sprites_template: "", - sprites_domain_name: "", - sprites_version_prefix: None, - glyphs_template: "", - glyphs_domain_name: "", - glyphs_version_prefix: None, - tile_template: "", - tile_domain_name: "", - tile_version_prefix: None, - api_key_parameter_name: "", - requires_api_key: false, - default_style: "", - } - "#); - assert_debug_snapshot!(TileServerOptions::default_mapbox(), @r#" - TileServerOptions { - base_url: "https://demotiles.maplibre.org", - uri_scheme_alias: "maplibre", - source_template: "/tiles/{domain}.json", - source_domain_name: "", - source_version_prefix: None, - style_template: "{path}.json", - style_domain_name: "maps", - style_version_prefix: None, - sprites_template: "/{path}/sprite{scale}.{format}", - sprites_domain_name: "", - sprites_version_prefix: None, - glyphs_template: "/font/{fontstack}/{start}-{end}.pbf", - glyphs_domain_name: "fonts", - glyphs_version_prefix: None, - tile_template: "/{path}", - tile_domain_name: "tiles", - tile_version_prefix: None, - api_key_parameter_name: "", - requires_api_key: false, - default_style: "Basic", - } - "#); - assert_debug_snapshot!(TileServerOptions::default_maplibre(), @r#" - TileServerOptions { - base_url: "https://api.mapbox.com", - uri_scheme_alias: "mapbox", - source_template: "/{domain}.json", - source_domain_name: "", - source_version_prefix: Some( - "/v4", - ), - style_template: "/styles/v1{path}", - style_domain_name: "styles", - style_version_prefix: None, - sprites_template: "/styles/v1{directory}{filename}/sprite{extension}", - sprites_domain_name: "sprites", - sprites_version_prefix: None, - glyphs_template: "/fonts/v1{path}", - glyphs_domain_name: "fonts", - glyphs_version_prefix: None, - tile_template: "{path}", - tile_domain_name: "tiles", - tile_version_prefix: Some( - "/v4", - ), - api_key_parameter_name: "access_token", - requires_api_key: true, - default_style: "Streets", - } - "#); - assert_debug_snapshot!(TileServerOptions::default_maptiler(), @r#" - TileServerOptions { - base_url: "https://api.maptiler.com", - uri_scheme_alias: "maptiler", - source_template: "/tiles{path}/tiles.json", - source_domain_name: "sources", - source_version_prefix: None, - style_template: "/maps{path}/style.json", - style_domain_name: "maps", - style_version_prefix: None, - sprites_template: "/maps{path}", - sprites_domain_name: "sprites", - sprites_version_prefix: None, - glyphs_template: "/fonts{path}", - glyphs_domain_name: "fonts", - glyphs_version_prefix: None, - tile_template: "{path}", - tile_domain_name: "tiles", - tile_version_prefix: None, - api_key_parameter_name: "key", - requires_api_key: true, - default_style: "Streets", - } - "#); - } - - #[test] - fn test_rust_wrapper() { - let result = get_42(); - assert_eq!(result, 42, "get_42() = 42"); - } - - #[test] - fn test_log2() { - let result = ceil_log2(1); - assert_eq!(result, 0, "log2(1) = 0 bits needed"); - - let result = ceil_log2(2); - assert_eq!(result, 1, "log2(2) = 1 bit needed"); - - let result = ceil_log2(3); - assert_eq!(result, 2, "log2(3) -> 2 bits needed"); + // fn withDefaultStyle(self: &TileServerOptions); + unsafe fn TileServerOptions_withDefaultStyle(obj: Pin<&mut TileServerOptions>, value: &str); + fn defaultStyle(self: &TileServerOptions) -> &CxxString; } } diff --git a/platform/rust/src/tile_server_options.rs b/platform/rust/src/tile_server_options.rs new file mode 100644 index 00000000000..17d7cd15c0e --- /dev/null +++ b/platform/rust/src/tile_server_options.rs @@ -0,0 +1,536 @@ +use std::ffi::{c_char, CStr, CString}; +use std::fmt; +use std::fmt::Debug; + +use cxx::{CxxString, UniquePtr}; + +use crate::ffi; + +pub struct TileServerOptions(UniquePtr); + +/// Convert a C string pointer to the Rust &CStr with lifetime of &self. +/// +/// # Safety +/// * as_ptr() inside C++ std::string is guaranteed to be null-terminated. +/// * The &CStr will remain valid as long as the TileServerOptions `&self` remains valid. +/// If some code tries to modify self, it will need to use &mut self, +/// which will not compile unless there are no &CStr references, as they use the same lifetime. +unsafe fn to_c_str(value: &CxxString) -> &CStr { + CStr::from_ptr(value.as_ptr().cast()) +} + +impl TileServerOptions { + /// Convert a pointer to a C string to an optional Rust &CStr with lifetime of &self. + /// + /// # Safety + /// The &CStr will remain valid as long as the TileServerOptions `&self` remains valid. + /// If some code tries to modify self, it will need to use &mut self, + /// which will not compile unless there are no &CStr references, as they use the same lifetime. + unsafe fn to_opt(&self, value: *const c_char) -> Option<&CStr> { + value.as_ref().map(|v| CStr::from_ptr(v)) + } + + /// Create a new default configuration + pub fn new() -> Self { + Self(ffi::TileServerOptions_new()) + } + + /// Get the tile server options configured for MapLibre. + pub fn default_mapbox() -> Self { + Self(ffi::TileServerOptions_mapbox()) + } + + /// Get the tile server options configured for Mapbox. + pub fn default_maplibre() -> Self { + Self(ffi::TileServerOptions_maplibre()) + } + + /// Get the tile server options configured for MapTiler. + pub fn default_maptiler() -> Self { + Self(ffi::TileServerOptions_maptiler()) + } + + /// Sets the API base URL + pub fn with_base_url(&mut self, base_url: &str) -> &mut Self { + ffi::TileServerOptions_withBaseURL(self.0.pin_mut(), base_url); + self + } + + /// Gets the base URL. + pub fn base_url(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.baseURL()) } + } + + /// Sets the scheme alias for the tile server. For example maptiler:// for MapTiler. + pub fn with_uri_scheme_alias(&mut self, alias: &str) -> &mut Self { + ffi::TileServerOptions_withUriSchemeAlias(self.0.pin_mut(), alias); + self + } + + /// Gets the URI scheme alias. + pub fn uri_scheme_alias(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.uriSchemeAlias()) } + } + + /// Sets the template for sources. + pub fn with_source_template( + &mut self, + source_template: &str, + domain_name: &str, + version_prefix: Option, + ) -> &mut Self { + unsafe { + // Slightly inefficient because CString allocation is than copied to std::string + let version_prefix = version_prefix + .as_ref() + .map(|v| v.as_ptr()) + .unwrap_or(std::ptr::null()); + ffi::TileServerOptions_withSourceTemplate( + self.0.pin_mut(), + source_template, + domain_name, + version_prefix, + ); + } + self + } + + /// Gets the source template. + pub fn source_template(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.sourceTemplate()) } + } + + /// Gets the source domain name. + pub fn source_domain_name(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.sourceDomainName()) } + } + + /// Gets the source version prefix. + pub fn source_version_prefix(&self) -> Option<&CStr> { + unsafe { self.to_opt(ffi::TileServerOptions_sourceVersionPrefix(&self.0)) } + } + + /// Sets the template for styles. + /// If set, the URL domain must contain the specified string to be matched as canonical style URL. + pub fn with_style_template( + &mut self, + style_template: &str, + domain_name: &str, + version_prefix: Option, + ) -> &mut Self { + unsafe { + // Slightly inefficient because CString allocation is than copied to std::string + let version_prefix = version_prefix + .as_ref() + .map(|v| v.as_ptr()) + .unwrap_or(std::ptr::null()); + ffi::TileServerOptions_withStyleTemplate( + self.0.pin_mut(), + style_template, + domain_name, + version_prefix, + ); + } + self + } + + /// Gets the style template. + pub fn style_template(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.styleTemplate()) } + } + + /// Gets the style domain name. + pub fn style_domain_name(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.styleDomainName()) } + } + + /// Gets the style version prefix. + pub fn style_version_prefix(&self) -> Option<&CStr> { + unsafe { self.to_opt(ffi::TileServerOptions_styleVersionPrefix(&self.0)) } + } + + /// Sets the template for sprites. + /// If set, the URL domain must contain the specified string to be matched as canonical sprite URL. + pub fn with_sprites_template( + &mut self, + sprites_template: &str, + domain_name: &str, + version_prefix: Option, + ) -> &mut Self { + unsafe { + // Slightly inefficient because CString allocation is than copied to std::string + let version_prefix = version_prefix + .as_ref() + .map(|v| v.as_ptr()) + .unwrap_or(std::ptr::null()); + ffi::TileServerOptions_withSpritesTemplate( + self.0.pin_mut(), + sprites_template, + domain_name, + version_prefix, + ); + } + self + } + + /// Gets the sprites template. + pub fn sprites_template(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.spritesTemplate()) } + } + + /// Gets the sprites domain name. + pub fn sprites_domain_name(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.spritesDomainName()) } + } + + /// Gets the sprites version prefix. + pub fn sprites_version_prefix(&self) -> Option<&CStr> { + unsafe { self.to_opt(ffi::TileServerOptions_spritesVersionPrefix(&self.0)) } + } + + /// Sets the template for glyphs. + /// If set, the URL domain must contain the specified string to be matched as canonical glyphs URL. + pub fn with_glyphs_template( + &mut self, + glyphs_template: &str, + domain_name: &str, + version_prefix: Option, + ) -> &mut Self { + unsafe { + // Slightly inefficient because CString allocation is than copied to std::string + let version_prefix = version_prefix + .as_ref() + .map(|v| v.as_ptr()) + .unwrap_or(std::ptr::null()); + ffi::TileServerOptions_withGlyphsTemplate( + self.0.pin_mut(), + glyphs_template, + domain_name, + version_prefix, + ); + } + self + } + + /// Gets the glyphs template. + pub fn glyphs_template(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.glyphsTemplate()) } + } + + /// Gets the glyphs domain name. + pub fn glyphs_domain_name(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.glyphsDomainName()) } + } + + /// Gets the glyphs version prefix. + pub fn glyphs_version_prefix(&self) -> Option<&CStr> { + unsafe { self.to_opt(ffi::TileServerOptions_glyphsVersionPrefix(&self.0)) } + } + + /// Sets the template for tiles. + /// + /// If set, the URL domain must contain the specified string to be matched as canonical tile URL. + pub fn with_tile_template( + &mut self, + tile_template: &str, + domain_name: &str, + version_prefix: Option, + ) -> &mut Self { + unsafe { + // Slightly inefficient because CString allocation is than copied to std::string + let version_prefix = version_prefix + .as_ref() + .map(|v| v.as_ptr()) + .unwrap_or(std::ptr::null()); + ffi::TileServerOptions_withTileTemplate( + self.0.pin_mut(), + tile_template, + domain_name, + version_prefix, + ); + } + self + } + + /// Gets the tile template. + pub fn tile_template(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.tileTemplate()) } + } + + /// Gets the tile domain name. + pub fn tile_domain_name(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.tileDomainName()) } + } + + /// Gets the tile version prefix. + pub fn tile_version_prefix(&self) -> Option<&CStr> { + unsafe { self.to_opt(ffi::TileServerOptions_tileVersionPrefix(&self.0)) } + } + + /// Sets the access token parameter name. + pub fn with_api_key_parameter_name(&mut self, api_key_parameter_name: &str) -> &mut Self { + unsafe { + ffi::TileServerOptions_withApiKeyParameterName( + self.0.pin_mut(), + api_key_parameter_name, + ); + } + self + } + + /// Gets the API key parameter name. + pub fn api_key_parameter_name(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.apiKeyParameterName()) } + } + + /// Sets if an API key is required. + pub fn set_requires_api_key(&mut self, api_key_required: bool) -> &mut Self { + ffi::TileServerOptions_setRequiresApiKey(self.0.pin_mut(), api_key_required); + self + } + + /// Checks if an API key is required. + pub fn requires_api_key(self: &TileServerOptions) -> bool { + self.0.requiresApiKey() + } + + // /// Gets the default styles. + //// #[cxx_name = "defaultStyles"] + // const std::vector defaultStyles() const; + + // /// Sets the collection default styles. + //// #[cxx_name = "withDefaultStyles"] + // TileServerOptions& withDefaultStyles(std::vector styles); + + /// Sets the default style by name. The style name must exist in defaultStyles collection. + pub fn with_default_style(&mut self, default_style: &str) -> &mut Self { + unsafe { + ffi::TileServerOptions_withDefaultStyle(self.0.pin_mut(), default_style); + } + self + } + + /// Gets the default style. + pub fn default_style(self: &TileServerOptions) -> &CStr { + unsafe { to_c_str(self.0.defaultStyle()) } + } +} + +impl Debug for TileServerOptions { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TileServerOptions") + .field("base_url", &self.base_url()) + .field("uri_scheme_alias", &self.uri_scheme_alias()) + .field("source_template", &self.source_template()) + .field("source_domain_name", &self.source_domain_name()) + .field("source_version_prefix", &self.source_version_prefix()) + .field("style_template", &self.style_template()) + .field("style_domain_name", &self.style_domain_name()) + .field("style_version_prefix", &self.style_version_prefix()) + .field("sprites_template", &self.sprites_template()) + .field("sprites_domain_name", &self.sprites_domain_name()) + .field("sprites_version_prefix", &self.sprites_version_prefix()) + .field("glyphs_template", &self.glyphs_template()) + .field("glyphs_domain_name", &self.glyphs_domain_name()) + .field("glyphs_version_prefix", &self.glyphs_version_prefix()) + .field("tile_template", &self.tile_template()) + .field("tile_domain_name", &self.tile_domain_name()) + .field("tile_version_prefix", &self.tile_version_prefix()) + .field("api_key_parameter_name", &self.api_key_parameter_name()) + .field("requires_api_key", &self.requires_api_key()) + .field("default_style", &self.default_style()) + .finish() + } +} + +#[cfg(test)] +mod tests { + use insta::assert_debug_snapshot; + + use super::*; + + #[test] + fn test_setters() { + let mut opts = TileServerOptions::new(); + opts.with_base_url("https://example.com") + .with_uri_scheme_alias("example") + .with_source_template("/tiles/{domain}.json", "source_example", None) + .with_style_template("{path}.json", "style_example", None) + .with_sprites_template("/{path}/sprite{scale}.{format}", "sprites_example", None) + .with_glyphs_template( + "/font/{fontstack}/{start}-{end}.pbf", + "glyphs_example", + None, + ) + .with_tile_template("/{path}", "tiles_example", None) + .with_api_key_parameter_name("api-key") + .set_requires_api_key(true) + .with_default_style("abc"); + + assert_debug_snapshot!(opts, @r#" + TileServerOptions { + base_url: "https://example.com", + uri_scheme_alias: "example", + source_template: "/tiles/{domain}.json", + source_domain_name: "source_example", + source_version_prefix: None, + style_template: "{path}.json", + style_domain_name: "style_example", + style_version_prefix: None, + sprites_template: "/{path}/sprite{scale}.{format}", + sprites_domain_name: "sprites_example", + sprites_version_prefix: None, + glyphs_template: "/font/{fontstack}/{start}-{end}.pbf", + glyphs_domain_name: "glyphs_example", + glyphs_version_prefix: None, + tile_template: "/{path}", + tile_domain_name: "tiles_example", + tile_version_prefix: None, + api_key_parameter_name: "api-key", + requires_api_key: true, + default_style: "abc", + } + "#); + + opts.with_source_template( + "/tiles/{domain}.json", + "source_example", + Some(CString::new("/source1").unwrap()), + ) + .with_style_template( + "{path}.json", + "style_example", + Some(CString::new("/style1").unwrap()), + ) + .with_sprites_template( + "/{path}/sprite{scale}.{format}", + "sprites_example", + Some(CString::new("/sprites1").unwrap()), + ) + .with_glyphs_template( + "/font/{fontstack}/{start}-{end}.pbf", + "glyphs_example", + Some(CString::new("/glyphs1").unwrap()), + ) + .with_tile_template( + "/{path}", + "tiles_example", + Some(CString::new("/tiles1").unwrap()), + ); + + assert_debug_snapshot!(opts, @r#" + TileServerOptions { + base_url: "https://example.com", + uri_scheme_alias: "example", + source_template: "/tiles/{domain}.json", + source_domain_name: "source_example", + source_version_prefix: Some( + "/source1", + ), + style_template: "{path}.json", + style_domain_name: "style_example", + style_version_prefix: Some( + "/style1", + ), + sprites_template: "/{path}/sprite{scale}.{format}", + sprites_domain_name: "sprites_example", + sprites_version_prefix: Some( + "/sprites1", + ), + glyphs_template: "/font/{fontstack}/{start}-{end}.pbf", + glyphs_domain_name: "glyphs_example", + glyphs_version_prefix: Some( + "/glyphs1", + ), + tile_template: "/{path}", + tile_domain_name: "tiles_example", + tile_version_prefix: Some( + "/tiles1", + ), + api_key_parameter_name: "api-key", + requires_api_key: true, + default_style: "abc", + } + "#); + } + + #[test] + fn test_defaults() { + assert_debug_snapshot!(TileServerOptions::new(), @r#" + TileServerOptions { + base_url: "", + uri_scheme_alias: "", + source_template: "", + source_domain_name: "", + source_version_prefix: None, + style_template: "", + style_domain_name: "", + style_version_prefix: None, + sprites_template: "", + sprites_domain_name: "", + sprites_version_prefix: None, + glyphs_template: "", + glyphs_domain_name: "", + glyphs_version_prefix: None, + tile_template: "", + tile_domain_name: "", + tile_version_prefix: None, + api_key_parameter_name: "", + requires_api_key: false, + default_style: "", + } + "#); + assert_debug_snapshot!(TileServerOptions::default_maplibre(), @r#" + TileServerOptions { + base_url: "https://api.mapbox.com", + uri_scheme_alias: "mapbox", + source_template: "/{domain}.json", + source_domain_name: "", + source_version_prefix: Some( + "/v4", + ), + style_template: "/styles/v1{path}", + style_domain_name: "styles", + style_version_prefix: None, + sprites_template: "/styles/v1{directory}{filename}/sprite{extension}", + sprites_domain_name: "sprites", + sprites_version_prefix: None, + glyphs_template: "/fonts/v1{path}", + glyphs_domain_name: "fonts", + glyphs_version_prefix: None, + tile_template: "{path}", + tile_domain_name: "tiles", + tile_version_prefix: Some( + "/v4", + ), + api_key_parameter_name: "access_token", + requires_api_key: true, + default_style: "Streets", + } + "#); + assert_debug_snapshot!(TileServerOptions::default_maptiler(), @r#" + TileServerOptions { + base_url: "https://api.maptiler.com", + uri_scheme_alias: "maptiler", + source_template: "/tiles{path}/tiles.json", + source_domain_name: "sources", + source_version_prefix: None, + style_template: "/maps{path}/style.json", + style_domain_name: "maps", + style_version_prefix: None, + sprites_template: "/maps{path}", + sprites_domain_name: "sprites", + sprites_version_prefix: None, + glyphs_template: "/fonts{path}", + glyphs_domain_name: "fonts", + glyphs_version_prefix: None, + tile_template: "{path}", + tile_domain_name: "tiles", + tile_version_prefix: None, + api_key_parameter_name: "key", + requires_api_key: true, + default_style: "Streets", + } + "#); + } +}