Rust Code Style#
Prefer Box<[T]>
(boxed slices) over Vec<T>
for large collections#
while a Vec<T>
is more common, it lacks the ability to match capacity exactly with length unless it is set beforehand. in many cases this is not possible. when dealing with large persistent datasets such as Graph
and TraversalModel
data, we want to store that data in a Box<[T]>
. when constructing the dataset, the Vec
can be used, and then converted to a Box<[T]>
afterward via into_boxed_slice
:
let path: Path = todo!();
let data: Vec<T> = read_utils::from_csv(&file_path, true, None, None, None)?;
let output: Box<[T]> = data.into_boxed_slice();
Vec
is preferred for smaller or non-persistent datasets, or when the additional features of Vec
are used, such as iteration or dynamic allocation.
The Builder, Service, Model Convention in RouteE Compass#
in RouteE Compass, large Traversal and Frontier objects are loaded once and shared across threads. they are built in two phases: once at application initialization, and once again for each query, so that query-specific parameters can be applied. these phases are represented by the following types:
phase |
description |
lifetime |
Frontier |
Traversal |
---|---|---|---|---|
builder |
an empty struct with a |
app initialization only |
|
|
service |
struct with a |
entire program lifetime (same as CompassApp instance) |
|
|
model |
object used by the search algorithm |
duration of a single query |
|
|
when we apply the build
methods, we get these results (using the travel time TraversalModel
as an example):
let config: serde_json::Value = json!(); // application configuration
let query: serde_json::Value = json!(); // a single user search query
let builder: Box<dyn TraversalModelBuilder> = Box::new(SpeedLookupBuilder {});
let service: Arc<dyn TraversalModelService> = builder.build(&config)?;
let model: Arc<dyn TraversalModel> = service.build(&query);
the builder object instances are wrapped in a Box
referenced by the CompassAppBuilder
and used when creating CompassApp
instances. once we build a service from the builder, the app requires that they are wrapped in an Arc
, which is a thread-safe pointer. this way, the service can be shared across threads so we can build a model for a specific user query from within a query thread.