| Crates.io | fcb_core |
| lib.rs | fcb_core |
| version | 0.6.0 |
| created_at | 2025-06-17 11:45:04.627273+00 |
| updated_at | 2025-12-19 15:38:31.7605+00 |
| description | FlatCityBuf is a library for reading and writing CityJSON with FlatBuffers. Contains code derived from FlatGeobuf (BSD-2-Clause) for spatial indexing. |
| homepage | |
| repository | https://github.com/HideBa/flatcitybuf |
| max_upload_size | |
| id | 1715584 |
| size | 7,895,950 |
A high-performance Rust library for encoding and decoding CityJSON data to the FlatCityBuf (FCB) binary format. FCB uses FlatBuffers for efficient serialization with support for spatial and attribute indexing.
Add this to your Cargo.toml:
[dependencies]
fcb_core = "0.1.0"
# For HTTP support
fcb_core = { version = "0.1.0", features = ["http"] }
use fcb_core::{
FcbWriter, HeaderWriterOptions, AttributeSchema, AttributeSchemaMethods,
read_cityjson_from_reader, CJTypeKind
};
use std::fs::File;
use std::io::{BufReader, BufWriter};
// read cityjson data
let input_file = File::open("input.city.jsonl")?;
let input_reader = BufReader::new(input_file);
let cj_seq = read_cityjson_from_reader(input_reader, CJTypeKind::Seq)?;
if let CJType::Seq(cj_seq) = cj_seq {
// build attribute schema
let mut attr_schema = AttributeSchema::new();
for feature in cj_seq.features.iter() {
for (_, co) in feature.city_objects.iter() {
if let Some(attributes) = &co.attributes {
attr_schema.add_attributes(attributes);
}
}
}
// configure writer options
let attr_indices = vec![
("building_type".to_string(), None),
("height".to_string(), None),
];
let header_options = HeaderWriterOptions {
write_index: true,
feature_count: cj_seq.features.len() as u64,
index_node_size: 16,
attribute_indices: Some(attr_indices),
geographical_extent: None,
};
// create writer and add features
let output_file = File::create("output.fcb")?;
let output_writer = BufWriter::new(output_file);
let mut fcb = FcbWriter::new(
cj_seq.cj,
Some(header_options),
Some(attr_schema),
None
)?;
for feature in cj_seq.features.iter() {
fcb.add_feature(feature)?;
}
fcb.write(output_writer)?;
}
you can also use the fcb_cli to serialize CityJSON to FCB. Check the CLI README for more details.
use fcb_core::{FcbReader, deserializer::to_cj_metadata};
use std::fs::File;
use std::io::BufReader;
let input_file = File::open("input.fcb")?;
let input_reader = BufReader::new(input_file);
let mut reader = FcbReader::open(input_reader)?.select_all()?;
let header = reader.header();
let cj_metadata = to_cj_metadata(&header)?;
println!("features: {}", header.features_count());
while let Some(feature_buf) = reader.next()? {
let cj_feature = feature_buf.cur_cj_feature()?;
// process feature
println!("feature id: {}", cj_feature.id);
}
use fcb_core::{FcbReader, packed_rtree::Query};
let mut reader = FcbReader::open(input_reader)?
.select_query(Query::BBox(minx, miny, maxx, maxy))?;
while let Some(feature_buf) = reader.next()? {
let cj_feature = feature_buf.cur_cj_feature()?;
// process spatially filtered feature
}
use fcb_core::{FcbReader, KeyType, Operator, FixedStringKey, Float};
let query = vec![
(
"height".to_string(),
Operator::Gt,
KeyType::Float64(Float(10.0)),
),
(
"building_type".to_string(),
Operator::Eq,
KeyType::StringKey50(FixedStringKey::from_str("residential")),
),
];
let mut reader = FcbReader::open(input_reader)?.select_attr_query(query)?;
while let Some(feature_buf) = reader.next()? {
let cj_feature = feature_buf.cur_cj_feature()?;
// process filtered features
}
use fcb_core::HttpFcbReader;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let http_reader = HttpFcbReader::open("https://example.com/data.fcb").await?;
// spatial query over http
let mut iter = http_reader
.select_query(Query::BBox(minx, miny, maxx, maxy))
.await?;
while let Some(feature) = iter.next().await? {
let cj_feature = feature.cj_feature()?;
// process feature streamed over http
}
Ok(())
}
Portions of this software are derived from FlatGeobuf (BSD 2-Clause License). See ATTRIBUTION.md for detailed attribution information.
FcbWriter<'a>Main writer for serializing CityJSON to FCB format.
Methods:
new(cj, header_options, attr_schema, semantic_attr_schema) -> Result<Self>add_feature(&mut self, feature) -> Result<()>write(self, output) -> Result<()>FcbReader<R>Reader for deserializing FCB files.
Methods:
open(reader) -> Result<Self>select_all(self) -> Result<FeatureIter<R, Seekable>>select_query(self, query) -> Result<FeatureIter<R, Seekable>>select_attr_query(self, query) -> Result<FeatureIter<R, Seekable>>select_all_seq(self) -> Result<FeatureIter<R, NotSeekable>>select_query_seq(self, query) -> Result<FeatureIter<R, NotSeekable>>select_attr_query_seq(self, query) -> Result<FeatureIter<R, NotSeekable>>HttpFcbReader<T>HTTP-based streaming reader.
Methods:
open(url) -> Result<Self>select_all(self) -> Result<AsyncFeatureIter<T>>select_query(self, query) -> Result<AsyncFeatureIter<T>>select_attr_query(self, query) -> Result<AsyncFeatureIter<T>>HeaderWriterOptionsConfiguration for FCB header writing.
pub struct HeaderWriterOptions {
pub write_index: bool,
pub feature_count: u64,
pub index_node_size: u16,
pub attribute_indices: Option<Vec<(String, Option<u16>)>>,
pub geographical_extent: Option<[f64; 6]>,
}
AttributeSchemaSchema for managing attribute types and indexing.
Methods:
new() -> Selfadd_attributes(&mut self, attributes)get(&self, name) -> Option<(u16, ColumnType)>use fcb_core::packed_rtree::Query;
// bounding box query
let bbox_query = Query::BBox(minx, miny, maxx, maxy);
use fcb_core::{KeyType, Operator, FixedStringKey, Float};
type AttrQuery = Vec<(String, Operator, KeyType)>;
// numeric comparison
let height_query = (
"height".to_string(),
Operator::Gt,
KeyType::Float64(Float(10.0))
);
// string exact match
let type_query = (
"building_type".to_string(),
Operator::Eq,
KeyType::StringKey50(FixedStringKey::from_str("residential"))
);
// datetime comparison
let date_query = (
"registration_date".to_string(),
Operator::Gt,
KeyType::DateTime(chrono::DateTime::from_str("2020-01-01T00:00:00Z")?)
);
Operator::Eq - equalsOperator::Gt - greater thanOperator::Lt - less thanOperator::Gte - greater than or equalOperator::Lte - less than or equalKeyType::Float64(Float) - 64-bit floating pointKeyType::StringKey50(FixedStringKey) - fixed-length strings up to 50 charsKeyType::DateTime(chrono::DateTime<Utc>) - datetime valuesKeyType::UByte(u8) - unsigned 8-bit integerThe library uses thiserror for structured error handling:
use fcb_core::error::{Error, Result};
match fcb_reader.select_all() {
Ok(reader) => {
// process features
}
Err(Error::NoIndex) => {
println!("file has no spatial index");
}
Err(Error::AttributeIndexNotFound) => {
println!("no attribute index found");
}
Err(e) => {
println!("error: {}", e);
}
}
Enable optional features in Cargo.toml:
[dependencies]
fcb_core = { version = "0.1.0", features = ["http"] }
http - enables HTTP streaming capabilitiesSee the tests/ directory for comprehensive examples:
tests/attr_index.rs - attribute indexing and queryingtests/http.rs - HTTP streaming examplestests/e2e.rs - end-to-end serialization/deserializationtests/read.rs - various reading patternsMIT License - see LICENSE file for details.