rsc_osrm 0.1.56

rust wrapper for osrm, folk from TehGoat/rs_osrm
use crate::general::c_string_to_string;
use crate::general::COsrmRoute;
use crate::general::Coordinate;
use crate::general::Route;
use crate::general::{CGeneralOptions, GeneralOptions};
use crate::route::AnnotationsType;
use crate::route::GeometriesType;
use crate::route::OverviewType;
use crate::Osrm;
use crate::{Boolean, Status};
use core::slice;
use std::ffi::CStr;
use std::os::raw::c_double;
use std::os::raw::{c_char, c_int, c_void};

#[link(name = "c_osrm")]
extern "C" {
    fn trip_result_destroy(result: *mut CTripResult);

    fn osrm_trip(
        osrm: *mut c_void,
        request: *mut CTripRequest,
        result: *mut *mut CTripResult,
    ) -> Status;
}

#[repr(C)]
#[derive(Clone)]
pub enum trip_start {
    StartAny,
    First,
}

#[repr(C)]
#[derive(Clone)]
pub enum trip_end {
    EndAny,
    Last,
}

#[repr(C)]
#[derive(Clone)]
struct CTripWaypoint {
    hint: *const c_char,
    distance: c_double,
    name: *const c_char,
    location: [c_double; 2],
    trips_index: c_int,
    waypoint_index: c_int,
}

pub struct TripWaypoint {
    pub hint: Option<String>,
    pub distance: f64,
    pub name: String,
    pub location: [f64; 2],
    pub trips_index: i32,
    pub waypoint_index: i32,
}

impl TripWaypoint {
    fn new(c_waypoints: &CTripWaypoint) -> TripWaypoint {
        let mut hint: Option<String> = None;
        if c_waypoints.hint != std::ptr::null() {
            hint = Option::from(c_string_to_string(c_waypoints.hint));
        }

        TripWaypoint {
            hint,
            distance: c_waypoints.distance,
            name: c_string_to_string(c_waypoints.name),
            location: c_waypoints.location,
            trips_index: c_waypoints.trips_index,
            waypoint_index: c_waypoints.waypoint_index,
        }
    }
}

#[repr(C)]
struct CTripRequest {
    general_options: CGeneralOptions,
    roundtrip: Boolean,
    source: trip_start,
    destination: trip_end,
    steps: Boolean,
    annotations: Boolean,
    annotations_type: AnnotationsType,
    geometries: GeometriesType,
    overview: OverviewType,
}

impl CTripRequest {
    fn new(request: &mut TripRequest) -> CTripRequest {
        CTripRequest {
            general_options: CGeneralOptions::new(&mut request.general_options),
            roundtrip: Boolean::from(request.roundtrip),
            source: request.source.clone(),
            destination: request.destination.clone(),
            steps: Boolean::from(request.steps),
            annotations: Boolean::from(request.annotations),
            annotations_type: request.annotations_type.clone(),
            geometries: request.geometries.clone(),
            overview: request.overview.clone(),
        }
    }
}

pub struct TripRequest {
    general_options: GeneralOptions,
    roundtrip: bool,
    source: trip_start,
    destination: trip_end,
    steps: bool,
    annotations: bool,
    annotations_type: AnnotationsType,
    geometries: GeometriesType,
    overview: OverviewType,
}

impl TripRequest {
    pub fn new(coordinates: &Vec<Coordinate>) -> TripRequest {
        TripRequest {
            general_options: GeneralOptions::new(coordinates),
            roundtrip: true,
            source: trip_start::StartAny,
            destination: trip_end::EndAny,
            steps: false,
            annotations: false,
            annotations_type: AnnotationsType::None,
            geometries: GeometriesType::Polyline,
            overview: OverviewType::Simplified,
        }
    }

    pub fn run(&mut self, osrm: &Osrm) -> (Status, TripResult) {
        unsafe {
            let mut result: *mut CTripResult = std::ptr::null_mut();
            let result_ptr: *mut *mut CTripResult = &mut result;

            let status = osrm_trip(
                *osrm.config,
                &mut CTripRequest::new(self) as *mut CTripRequest,
                result_ptr,
            );

            let converted_result = TripResult::new(&(*result));

            trip_result_destroy(result);

            (status, converted_result)
        }
    }
}

#[repr(C)]
struct CTripResult {
    code: *const c_char,
    message: *const c_char,
    waypoints: *const CTripWaypoint,
    number_of_waypoints: c_int,
    trips: *const COsrmRoute,
    number_of_trips: c_int,
}

pub struct TripResult {
    pub code: Option<String>,
    pub message: Option<String>,
    pub waypoints: Vec<TripWaypoint>,
    pub trips: Vec<Route>,
}

impl TripResult {
    fn new(c_reasult: &CTripResult) -> TripResult {
        let mut code: Option<String> = None;
        if c_reasult.code != std::ptr::null_mut() {
            let c_code_buf: *const c_char = c_reasult.code;
            let c_code_str: &CStr = unsafe { CStr::from_ptr(c_code_buf) };
            let code_str_slice: &str = c_code_str.to_str().unwrap();
            code = Option::from(code_str_slice.to_owned());
        }

        let mut message: Option<String> = None;
        if c_reasult.message != std::ptr::null_mut() {
            let c_message_buf: *const c_char = c_reasult.message;
            let c_message_str: &CStr = unsafe { CStr::from_ptr(c_message_buf) };
            let message_str_slice: &str = c_message_str.to_str().unwrap();
            message = Option::from(message_str_slice.to_owned());
        }

        let mut waypoints: Vec<TripWaypoint> = Vec::new();
        if c_reasult.waypoints != std::ptr::null_mut() {
            let waypoints_vec = unsafe {
                slice::from_raw_parts(c_reasult.waypoints, c_reasult.number_of_waypoints as usize)
                    .to_vec()
            };

            for waypoint in &waypoints_vec {
                waypoints.push(TripWaypoint::new(waypoint));
            }
        }

        let mut trips: Vec<Route> = Vec::new();
        if c_reasult.trips != std::ptr::null_mut() {
            let routes_vec = unsafe {
                slice::from_raw_parts(c_reasult.trips, c_reasult.number_of_trips as usize).to_vec()
            };

            for route in routes_vec {
                trips.push(route.to_route());
            }
        }

        TripResult {
            code,
            message,
            waypoints,
            trips,
        }
    }
}