rsc_osrm 0.1.56

rust wrapper for osrm, folk from TehGoat/rs_osrm
use crate::general::Approach;
use crate::general::Coordinate;
use crate::general::Waypoint;
use crate::general::{CGeneralOptions, CWaypoint, GeneralOptions, Bearing};
use crate::{Osrm, Status};
use core::slice;
use std::ffi::CStr;
use std::os::raw::{c_char, c_double, c_int, c_void};

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

    fn osrm_table(
        osrm: *mut c_void,
        request: *mut CTableRequest,
        result: *mut *mut CTableResult,
    ) -> Status;
}

#[repr(C)]
#[derive(Clone)]
pub enum Annotations {
    NONE = 0,
    DURATION = 1,
    DISTANCE = 2,
    ALL = 3,
}

#[repr(C)]
#[derive(Clone)]
pub enum FallbackCoordinate {
    INPUT = 0,
    SNAPPED = 1,
}

#[repr(C)]
struct CTableRequest {
    general_options: CGeneralOptions,
    sources: *const c_int,
    number_of_sources: c_int,
    destinations: *const c_int,
    number_of_destinations: c_int,
    annotations: Annotations,
    fallback_speed: c_double,
    fallback_coordinate: FallbackCoordinate,
    scale_factor: c_double,
}

impl CTableRequest {
    fn new(request: &mut TableRequest) -> CTableRequest {
        let mut c_request = CTableRequest {
            general_options: CGeneralOptions::new(&mut request.general_options),
            sources: std::ptr::null(),
            number_of_sources: 0,
            destinations: std::ptr::null(),
            number_of_destinations: 0,
            annotations: request.annotations.clone(),
            fallback_speed: request.fallback_speed,
            fallback_coordinate: request.fallback_coordinate.clone(),
            scale_factor: request.scale_factor,
        };

        if request.sources.is_some() {
            let sources = request.sources.as_ref().unwrap();
            c_request.sources = sources.as_ptr();
            c_request.number_of_sources = sources.len() as c_int;
        }

        if request.destinations.is_some() {
            let destinations = request.destinations.as_ref().unwrap();
            c_request.destinations = destinations.as_ptr();
            c_request.number_of_destinations = destinations.len() as c_int;
        }

        c_request
    }
}

#[repr(C)]
struct CTableResult {
    code: *const c_char,
    message: *const c_char,
    durations: *const f64,
    distances: *const f64,
    sources: *const CWaypoint,
    destinations: *const CWaypoint,
    number_of_sources: c_int,
    number_of_destinations: c_int,
}

#[derive(Debug)]
pub struct TableResult {
    pub code: Option<String>,
    pub message: Option<String>,
    pub durations: Option<Vec<Vec<f64>>>,
    pub distances: Option<Vec<Vec<f64>>>,
    pub sources: Option<Vec<Waypoint>>,
    pub destinations: Option<Vec<Waypoint>>,
}

impl TableResult {
    fn new(c_reasult: &CTableResult) -> TableResult {
        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 durations: Option<Vec<Vec<f64>>> = None;
        if c_reasult.durations != std::ptr::null_mut() {
            let durations_vec = unsafe {
                slice::from_raw_parts(
                    c_reasult.durations,
                    (c_reasult.number_of_sources * c_reasult.number_of_destinations) as usize,
                )
            };

            let mut rs_vec = Vec::new();
            for i in 0..c_reasult.number_of_sources {
                let mut rs_tmp_vec = Vec::new();
                for j in 0..c_reasult.number_of_destinations {
                    rs_tmp_vec
                        .push(durations_vec[(i * c_reasult.number_of_destinations + j) as usize]);
                }
                rs_vec.push(rs_tmp_vec);
            }

            durations = Option::from(rs_vec);
        }

        let mut distances: Option<Vec<Vec<f64>>> = None;
        if c_reasult.distances != std::ptr::null_mut() {
            let distances_vec = unsafe {
                slice::from_raw_parts(
                    c_reasult.distances,
                    (c_reasult.number_of_sources * c_reasult.number_of_destinations) as usize,
                )
            };

            let mut rs_vec = Vec::new();
            for i in 0..c_reasult.number_of_sources {
                let mut rs_tmp_vec = Vec::new();
                for j in 0..c_reasult.number_of_destinations {
                    rs_tmp_vec
                        .push(distances_vec[(i * c_reasult.number_of_destinations + j) as usize]);
                }
                rs_vec.push(rs_tmp_vec);
            }

            distances = Option::from(rs_vec);
        }

        let mut sources: Option<Vec<Waypoint>> = None;
        if c_reasult.sources != std::ptr::null_mut() {
            let sources_vec = unsafe {
                slice::from_raw_parts(c_reasult.sources, c_reasult.number_of_sources as usize)
                    .to_vec()
            };

            let mut rs_vec = Vec::new();
            for source in &sources_vec {
                rs_vec.push(Waypoint::new(source));
            }

            sources = Option::from(rs_vec);
        }

        let mut destinations: Option<Vec<Waypoint>> = None;
        if c_reasult.destinations != std::ptr::null_mut() {
            let destinations_vec = unsafe {
                slice::from_raw_parts(
                    c_reasult.destinations,
                    c_reasult.number_of_destinations as usize,
                )
                .to_vec()
            };

            let mut rs_vec = Vec::new();
            for destination in &destinations_vec {
                rs_vec.push(Waypoint::new(destination));
            }

            destinations = Option::from(rs_vec);
        }

        TableResult {
            code,
            message,
            durations,
            distances,
            sources,
            destinations,
        }
    }
}

pub struct TableRequest {
    general_options: GeneralOptions,
    sources: Option<Vec<i32>>,
    destinations: Option<Vec<i32>>,
    annotations: Annotations,
    fallback_speed: f64,
    fallback_coordinate: FallbackCoordinate,
    scale_factor: f64,
}

impl TableRequest {
    pub fn new(coordinates: &Vec<Coordinate>) -> TableRequest {
        TableRequest {
            general_options: GeneralOptions::new(coordinates),
            sources: None,
            destinations: None,
            annotations: Annotations::DURATION,
            fallback_speed: std::f64::MAX,
            fallback_coordinate: FallbackCoordinate::INPUT,
            scale_factor: 1.0,
        }
    }

    pub fn approach(&mut self, approaches: Option<Vec<Option<Approach>>>) -> &mut TableRequest {
        self.general_options.approach = approaches;
        self
    }

    pub fn bearings(&mut self, bearings: Option<Vec<Option<Bearing>>>) -> &mut TableRequest {
        self.general_options.bearings = bearings;
        self
    }

    pub fn radiuses(&mut self, val: &Option<Vec<Option<f64>>>) -> &mut TableRequest {
        self.general_options.radiuses(val);
        self
    }

    pub fn exclude(&mut self, exclude: Option<Vec<String>>) -> &mut TableRequest {
        self.general_options.exclude(&exclude);
        self
    }

    pub fn snap_avoid(&mut self, snap_avoid: Option<Vec<String>>) -> &mut TableRequest {
        self.general_options.snap_avoid(&snap_avoid);
        self
    }

    pub fn annotations(&mut self, annotations: Annotations) -> &mut TableRequest {
        self.annotations = annotations;
        self
    }

    pub fn sources(&mut self, sources: Vec<i32>) -> &mut TableRequest {
        self.sources = Some(sources);
        self
    }

    pub fn destinations(&mut self, destinations: Vec<i32>) -> &mut TableRequest {
        self.destinations = Some(destinations);
        self
    }

    fn validate(&mut self) -> Result<(), String> {
        self.general_options.validate()
    }

    pub fn run(&mut self, osrm: &Osrm) -> (Status, TableResult) {
        if let Err(msg) = self.validate() {
            return (
                Status::Error,
                TableResult {
                    code: Some("Err".to_owned()),
                    message: Some(msg),
                    durations: None,
                    distances: None,
                    sources: None,
                    destinations: None,
                },
            );
        }
        unsafe {
            let mut result: *mut CTableResult = std::ptr::null_mut();
            let result_ptr: *mut *mut CTableResult = &mut result;

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

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

            table_result_destroy(result);

            (status, converted_result)
        }
    }
}