open_vector_tile/
lib.rs

1#![no_std]
2#![cfg_attr(not(any(target_arch = "wasm32", feature = "wasm")), forbid(unsafe_code))]
3#![deny(missing_docs)]
4//! # Open Vector Tile
5//!
6//! ## Description
7//!
8//! The `open-vector-tile` Rust crate provides functionalities to read and write
9//! Open Vector Tile Spec messages. This crate uses `no_std` and is intended to be available for
10//! embedded systems and WASM applications.
11//!
12//! Types of layers include:
13//! - Vector data - vector points, lines, and polygons with 3D coordinates, properties, and/or m-values
14//! - Image data - raster data that is RGB(A) encoded
15//! - Grid data: data that has a max-min range, works much like an image but has floating/double precision point values for each point on the grid
16//!
17//! ### Reading
18//!
19//! ```rust,ignore
20//! use open_vector_tile::{VectorTile, VectorLayerMethods};
21//!
22//! let data: Vec<u8> = vec![];
23//! let mut tile = VectorTile::new(data, None);
24//!
25//! // VECTOR API
26//!
27//! let landuse = tile.layer("landuse").unwrap();
28//!
29//! // grab the first feature
30//! let firstFeature = landuse.feature(0).unwrap();
31//! // grab the geometry
32//! let geometry = firstFeature.load_geometry();
33//!
34//! // OR specifically ask for a geometry type
35//! let points = firstFeature.load_points();
36//! let lines = firstFeature.load_lines();
37//!
38//! // If you want to take advantage of the pre-tessellated and indexed geometries
39//! // and you're loading the data for a renderer, you can grab the pre-tessellated geometry
40//! let (geometry_flat, indices) = firstFeature.load_geometry_flat();
41//!
42//! // IMAGE API
43//!
44//! let satellite = tile.images.get("satellite").unwrap();
45//! // grab the image data
46//! let data = &satellite.image;
47//!
48//! // GRID API
49//!
50//! let elevation = tile.grids.get("elevation").unwrap();
51//! // grab the grid data
52//! let data = &elevation.data;
53//! ```
54//!
55//! ### Writing
56//!
57//! ```rust
58//! // NOTE: Be sure to include the `serde_json` crate
59//! extern crate alloc;
60//! use open_vector_tile::{
61//! base::{
62//!     BaseVectorFeature, BaseVectorLayer, BaseVectorLines3DFeature, BaseVectorLinesFeature,
63//!     BaseVectorPoints3DFeature, BaseVectorPointsFeature, BaseVectorPolys3DFeature,
64//!     BaseVectorPolysFeature, BaseVectorTile,
65//! },
66//! open::{
67//!     Extent, FeatureType, GridData, ImageData, ImageType,
68//! },
69//! write_tile, Point, Point3D, VectorGeometry, VectorLayerMethods,
70//! VectorLine3DWithOffset, VectorLineWithOffset, VectorTile,
71//! };
72//! use s2json::{BBox, BBox3D, BBOX, ValuePrimitiveType, ValueType, PrimitiveValue, Value};
73//!
74//!
75//! // WRITE VECTOR DATA //-//-//-//-//-//-//-//-//-//-//
76//!
77//! let mut tile = BaseVectorTile::default();
78//!
79//! // setup the property shapes
80//!
81//! let example_value_str = r#"{
82//!     "a": -20,
83//!     "b": 1,
84//!     "c": 2.2
85//! }"#;
86//! let example_value = serde_json::from_str::<Value>(example_value_str).unwrap();
87//! let example_value_str_2 = r#"{
88//!     "a": -2,
89//!     "b": 1,
90//!     "c": 2.2
91//! }"#;
92//! let example_value2 = serde_json::from_str::<Value>(example_value_str_2).unwrap();
93//!
94//! let empty_value = Value::from([
95//!     ("a".to_string(), ValueType::Primitive(PrimitiveValue::I64(0))),
96//!     ("b".to_string(), ValueType::Primitive(PrimitiveValue::U64(0))),
97//!     ("c".to_string(), ValueType::Primitive(PrimitiveValue::F32(0.0))),
98//! ]);
99//!
100//! // WRITE THE POINTS
101//!
102//! let mut points_layer =
103//!     BaseVectorLayer::new("points".to_string(), 4096.into(), vec![], None, None);
104//!
105//! let feature = BaseVectorPointsFeature::new(
106//!     None,
107//!     vec![Point::new_with_m(0, 0, example_value2.clone())],
108//!     example_value.clone(),
109//!     None,
110//! );
111//! let feature2 = BaseVectorPointsFeature::new(
112//!     Some(1),
113//!     vec![Point::new_with_m(0, 0, example_value.clone()), Point::new(1, 1)],
114//!     example_value2.clone(),
115//!     Some(BBox::new(-1.1, 0.0, 1.0, 1.0)),
116//! );
117//!
118//! // add_features
119//! points_layer.add_feature(BaseVectorFeature::BaseVectorPointsFeature(feature));
120//! points_layer.add_feature(BaseVectorFeature::BaseVectorPointsFeature(feature2));
121//!
122//! tile.add_layer(points_layer);
123//!
124//! // Lastly build the tile:
125//! let open_tile_bytes = write_tile(Some(&mut tile), None, None);
126//!
127//!
128//! // WRITE IMAGE DATA //-//-//-//-//-//-//-//-//-//-//
129//!
130//! let image =
131//!   ImageData::new("test".to_string(), ImageType::AVIF, 2, 3, Vec::from([1, 2, 3, 10]));
132//!
133//! let open_tile_bytes = write_tile(None, Some(vec![&image]), None);
134//!
135//!
136//! // WRITE GRID DATA //-//-//-//-//-//-//-//-//-//-//
137//!
138//! let elevation_data = GridData::new(
139//!     "elevation".to_owned(),
140//!     8_192.into(),
141//!     512.0,
142//!     0.0,
143//!     0.0,
144//!     vec![-1.0, 2.0, 3.0, 4.0],
145//! );
146//! let open_tile_bytes = write_tile(None, None, Some(vec![&elevation_data]));
147//! ```
148
149extern crate alloc;
150extern crate pbf;
151
152/// Base Vector containers for Tiles, Layers, and Features
153pub mod base;
154/// Geometry utilities
155pub mod geometry;
156/// Mapbox specification for Layers and Features
157pub mod mapbox;
158/// Open specification for Layers and Features
159pub mod open;
160/// Utilities/functions that are useful across all specifications
161pub mod util;
162/// The vector feature struct that covers both "open" and "mapbox" specifications
163pub mod vector_feature;
164/// The vector tile struct that covers both "open" and "mapbox" specifications
165pub mod vector_tile;
166
167pub use geometry::*;
168pub use open::*;
169pub use util::*;
170pub use vector_feature::*;
171pub use vector_tile::*;
172
173#[cfg(any(target_arch = "wasm32", feature = "wasm"))]
174use alloc::{boxed::Box, slice};
175
176#[cfg(any(target_arch = "wasm32", feature = "wasm"))]
177use lol_alloc::{AssumeSingleThreaded, FreeListAllocator};
178
179// SAFETY: This application is single threaded, so using AssumeSingleThreaded is allowed.
180#[cfg(any(target_arch = "wasm32", feature = "wasm"))]
181#[global_allocator]
182static ALLOCATOR: AssumeSingleThreaded<FreeListAllocator> =
183    unsafe { AssumeSingleThreaded::new(FreeListAllocator::new()) };
184
185// #[cfg(any(target_arch = "wasm32", feature = "wasm"))]
186// mod wasm_specific {
187//     #[panic_handler]
188//     fn panic(_info: &core::panic::PanicInfo) -> ! {
189//         loop {}
190//     }
191// }
192
193/// Expose the function "create_vector_tile" to JavaScript
194/// Creates a new VectorTile instance given input buffer
195#[cfg(any(target_arch = "wasm32", feature = "wasm"))]
196#[unsafe(no_mangle)]
197pub extern "C" fn create_vector_tile(data_ptr: *const u8, data_len: usize) -> *mut VectorTile {
198    // Convert the pointer and length into a slice
199    let data_slice = unsafe { slice::from_raw_parts(data_ptr, data_len) };
200
201    // Convert slice into Vec<u8> (we need to box this data for ownership)
202    let data_vec = data_slice.to_vec();
203
204    // Create the VectorTile instance
205    let vector_tile = VectorTile::new(data_vec, None);
206
207    // Box it and return as raw pointer
208    Box::into_raw(Box::new(vector_tile))
209}
210
211/// Expose the function "free_vector_tile" to JavaScript
212/// Frees the VectorTile instance from memory
213#[cfg(any(target_arch = "wasm32", feature = "wasm"))]
214#[unsafe(no_mangle)]
215pub extern "C" fn free_vector_tile(ptr: *mut VectorTile) {
216    if !ptr.is_null() {
217        unsafe {
218            _ = Box::from_raw(ptr); // Deallocate memory
219        }
220    }
221}
222
223/// Free memory allocated regardless of the type
224#[cfg(any(target_arch = "wasm32", feature = "wasm"))]
225#[unsafe(no_mangle)]
226pub extern "C" fn free(ptr: *mut u8, size: usize) {
227    unsafe {
228        // Convert the pointer to a slice and then drop it
229        let _ = core::slice::from_raw_parts_mut(ptr, size);
230
231        // Deallocate the memory
232        alloc::alloc::dealloc(ptr as *mut u8, alloc::alloc::Layout::array::<u8>(size).unwrap());
233    }
234}