I am using the proj crate which itself is just a wrapper on the eponymous C library. It allows to convert any coordinates system into any other. Unfortunately the result of this conversion is weekly typed. Everything is a geo_types::Point
, no matter the coordinate system used. In my project, I uses 3 coordinates systems: EPSG:4326 (it's gps coordinates), EPSG:2154 (used by official french elevation files), and Mercator. I would like to use strong typing to avoid mistake. To do this, I could create 3 different types: Epsg4326
, Epsg2154
, and Mercator
. This would prevent any misuse as long as I correctly use the right type when parsing external input.
The next step would be to make it easy to convert between one coordinate system to the other by implementing the From
trait for all combination (since I use only 3 coordinates system, this means that I need 6 possible conversion which is totally manageable).
This is where things start to be complicated. The convert
function is a method of the Proj
struct which isn't Send
. Creating a Proj
instance is really expensive, so I can't do this otherwise the performance would be horrible:
impl From<Mercator> for Epsg4326 {
fn from(p: Mercator) -> Epsg4326 {
// creating the Proj is way to expensive, don't do it at each convertion
let convert = Proj::new_known_crs("merc", "EPSG:4326", None).unwrap();
let (lat, lon) = convert
.convert(Point::new(p.lon, p.lat)) // normalized order, longitude first
.unwrap()
.x_y();
Epsg3226(lat, lon)
}
}
My first idea was to use lazy_static to store the Proj
object in a static variable, but Proj
isn't Send
. Is there a way to store this Proj
instance somewhere that wouldn't hurt multi-thread performances, while being globally accessible? Maybe something like a thread-local singleton?
If it's not possible, this means that I would not be able to use the From
trait, and would need to use a conversion function that would take a Proj
instance as parameter, which is not as nice.