Skip to content

Commit

Permalink
FFI working!
Browse files Browse the repository at this point in the history
  • Loading branch information
Neil McAlister committed Aug 16, 2019
1 parent a04063d commit c0e6677
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"name": "(Windows) Launch",
"type": "cppvsdbg",
"request": "launch",
"program": "${workspaceFolder}/target/debug/scannit-cli.exe",
"program": "${workspaceFolder}/target/debug/scannit-core-cli.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
Expand Down
42 changes: 31 additions & 11 deletions scannit-core-ffi/src/ffi.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::models::FFIHistory;
use libc::c_char;
use std::ffi::CString;

Expand All @@ -10,29 +11,48 @@ pub fn free_string(s: *mut c_char) {
};
}

pub fn free_buffer<T>(buf: FFIBuffer<T>) {
let mut vector = unsafe { std::vec::Vec::from_raw_parts(buf.data, buf.len, buf.capacity) };
let reconstituted_vector = vector.as_mut_ptr();
unsafe {
Box::from_raw(reconstituted_vector);
}
pub fn free_byte_buffer(buf: FFIByteBuffer) {
unsafe { std::vec::Vec::from_raw_parts(buf.data, buf.len, buf.capacity) };
}

pub fn free_history_buffer(buf: FFIHistoryBuffer) {
unsafe { std::vec::Vec::from_raw_parts(buf.data, buf.len, buf.capacity) };
}

#[repr(C)]
pub struct FFIBuffer<T> {
data: *mut T,
pub struct FFIByteBuffer {
data: *mut u8,
len: usize,
capacity: usize,
}

impl<T> From<&mut Vec<T>> for FFIBuffer<T> {
impl From<&mut Vec<u8>> for FFIByteBuffer {
/// Transform the given vector into an FFI-friendly buffer.
/// Does NOT call forget() on the underlying vector.
fn from(val: &mut Vec<T>) -> Self {
fn from(val: &mut Vec<u8>) -> Self {
let data = val.as_mut_ptr();
let len = val.len();
let capacity = val.capacity();
FFIByteBuffer {
data,
len,
capacity,
}
}
}

pub struct FFIHistoryBuffer {
data: *mut FFIHistory,
len: usize,
capacity: usize,
}

impl From<&mut Vec<FFIHistory>> for FFIHistoryBuffer {
fn from(val: &mut Vec<FFIHistory>) -> Self {
let data = val.as_mut_ptr();
let len = val.len();
let capacity = val.capacity();
FFIBuffer::<T> {
FFIHistoryBuffer {
data,
len,
capacity,
Expand Down
26 changes: 15 additions & 11 deletions scannit-core-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ pub unsafe extern "C" fn create_travel_card(
e_ticket_size: usize,
history_ptr: *const u8,
history_size: usize,
) -> FFITravelCard {
) -> *mut FFITravelCard {
let app_info;
let control_info;
let period_pass;
let stored_value;
let e_ticket;
let history;

println!("Running in Rust...");

// Actual unsafety begins here
app_info = std::slice::from_raw_parts(app_info_ptr, app_info_size);
control_info = std::slice::from_raw_parts(control_info_ptr, control_info_size);
Expand All @@ -44,20 +46,22 @@ pub unsafe extern "C" fn create_travel_card(
history,
);

FFITravelCard::from_travel_card(travelcard)
let ffi_travel_card = FFITravelCard::from_travel_card(travelcard);
Box::into_raw(Box::from(ffi_travel_card))
}

#[no_mangle]
pub extern "C" fn free_travel_card(travel_card: FFITravelCard) {
pub unsafe extern "C" fn free_travel_card(travel_card_ptr: *mut FFITravelCard) {
let travel_card = Box::from_raw(travel_card_ptr);
ffi::free_string(travel_card.application_instance_id);
ffi::free_buffer(travel_card.history);
ffi::free_history_buffer(travel_card.history);

ffi::free_buffer(travel_card.period_pass.validity_area_1_value);
ffi::free_buffer(travel_card.period_pass.validity_area_2_value);
ffi::free_buffer(travel_card.period_pass.last_board_area_value);
ffi::free_byte_buffer(travel_card.period_pass.validity_area_1_value);
ffi::free_byte_buffer(travel_card.period_pass.validity_area_2_value);
ffi::free_byte_buffer(travel_card.period_pass.last_board_area_value);

ffi::free_buffer(travel_card.e_ticket.validity_area_value);
ffi::free_buffer(travel_card.e_ticket.period_pass_validity_area_value);
ffi::free_buffer(travel_card.e_ticket.extension_1_validity_area_value);
ffi::free_buffer(travel_card.e_ticket.extension_2_validity_area_value);
ffi::free_byte_buffer(travel_card.e_ticket.validity_area_value);
ffi::free_byte_buffer(travel_card.e_ticket.period_pass_validity_area_value);
ffi::free_byte_buffer(travel_card.e_ticket.extension_1_validity_area_value);
ffi::free_byte_buffer(travel_card.e_ticket.extension_2_validity_area_value);
}
46 changes: 23 additions & 23 deletions scannit-core-ffi/src/models.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::ffi::FFIBuffer;
use crate::ffi::{FFIHistoryBuffer, FFIByteBuffer};
use libc::c_char;
use scannit_core::eticket::ETicket;
use scannit_core::history::{History, TransactionType};
Expand Down Expand Up @@ -37,7 +37,7 @@ pub struct FFITravelCard {

pub e_ticket: FFIETicket,

pub history: FFIBuffer<FFIHistory>,
pub history: FFIHistoryBuffer,
}

impl FFITravelCard {
Expand Down Expand Up @@ -68,7 +68,7 @@ impl FFITravelCard {

e_ticket: FFIETicket::from_e_ticket(travel_card.e_ticket),

history: FFIBuffer::from(travel_card.history),
history: FFIHistoryBuffer::from(travel_card.history),
}
}
}
Expand All @@ -80,15 +80,15 @@ pub struct FFIPeriodPass {
pub validity_area_1_kind: ValidityAreaKind,
/// This is either a single positive integer, or short list of positive integers.
/// We'll represent it as something that's always an array.
pub validity_area_1_value: FFIBuffer<u8>,
pub validity_area_1_value: FFIByteBuffer,
pub period_start_date_1: UnixTimestamp,

pub product_code_2_kind: ProductCodeKind,
pub product_code_2_value: u16,
pub validity_area_2_kind: ValidityAreaKind,
/// This is either a single positive integer, or short list of positive integers.
/// We'll represent it as something that's always an array.
pub validity_area_2_value: FFIBuffer<u8>,
pub validity_area_2_value: FFIByteBuffer,
pub period_start_date_2: UnixTimestamp,

// Most recent card load:
Expand All @@ -108,7 +108,7 @@ pub struct FFIPeriodPass {
pub last_board_location_value: u16,
pub last_board_direction: BoardingDirection,
pub last_board_area_kind: ValidityAreaKind,
pub last_board_area_value: FFIBuffer<u8>,
pub last_board_area_value: FFIByteBuffer,
}

impl FFIPeriodPass {
Expand All @@ -117,13 +117,13 @@ impl FFIPeriodPass {
product_code_1_kind: ProductCodeKind::from(&period_pass.product_code_1),
product_code_1_value: u16::from(&period_pass.product_code_1),
validity_area_1_kind: ValidityAreaKind::from(&period_pass.validity_area_1),
validity_area_1_value: FFIBuffer::from(period_pass.validity_area_1),
validity_area_1_value: FFIByteBuffer::from(period_pass.validity_area_1),
period_start_date_1: period_pass.period_start_date_1.and_hms(0, 0, 0).timestamp(),

product_code_2_kind: ProductCodeKind::from(&period_pass.product_code_2),
product_code_2_value: u16::from(&period_pass.product_code_2),
validity_area_2_kind: ValidityAreaKind::from(&period_pass.validity_area_2),
validity_area_2_value: FFIBuffer::from(period_pass.validity_area_2),
validity_area_2_value: FFIByteBuffer::from(period_pass.validity_area_2),
period_start_date_2: period_pass.period_start_date_2.and_hms(0, 0, 0).timestamp(),

loaded_period_product_kind: ProductCodeKind::from(&period_pass.loaded_period_product),
Expand All @@ -140,7 +140,7 @@ impl FFIPeriodPass {
last_board_location_value: u16::from(&period_pass.last_board_location),
last_board_direction: period_pass.last_board_direction,
last_board_area_kind: ValidityAreaKind::from(&period_pass.last_board_area),
last_board_area_value: FFIBuffer::from(period_pass.last_board_area),
last_board_area_value: FFIByteBuffer::from(period_pass.last_board_area),
}
}
}
Expand All @@ -156,7 +156,7 @@ pub struct FFIETicket {
pub validity_area_kind: ValidityAreaKind,
/// This is either a single positive integer, or short list of positive integers.
/// We'll represent it as something that's always an array.
pub validity_area_value: FFIBuffer<u8>,
pub validity_area_value: FFIByteBuffer,
pub sale_datetime: UnixTimestamp,
pub sale_device_kind: SaleDeviceKind,
pub sale_device_value: u16,
Expand All @@ -169,18 +169,18 @@ pub struct FFIETicket {
pub period_pass_validity_area_kind: ValidityAreaKind,
/// This is either a single positive integer, or short list of positive integers.
/// We'll represent it as something that's always an array.
pub period_pass_validity_area_value: FFIBuffer<u8>,
pub period_pass_validity_area_value: FFIByteBuffer,
pub extension_product_code_kind: ProductCodeKind,
pub extension_product_code_value: u16,
pub extension_1_validity_area_kind: ValidityAreaKind,
/// This is either a single positive integer, or short list of positive integers.
/// We'll represent it as something that's always an array.
pub extension_1_validity_area_value: FFIBuffer<u8>,
pub extension_1_validity_area_value: FFIByteBuffer,
pub extension_1_fare_cents: u16,
pub extension_2_validity_area_kind: ValidityAreaKind,
/// This is either a single positive integer, or short list of positive integers.
/// We'll represent it as something that's always an array.
pub extension_2_validity_area_value: FFIBuffer<u8>,
pub extension_2_validity_area_value: FFIByteBuffer,
pub extension_2_fare_cents: u16,
pub sale_status: bool,

Expand Down Expand Up @@ -209,7 +209,7 @@ impl FFIETicket {
validity_length_kind: ValidityLengthKind::from(&e_ticket.validity_length),
validity_length_value: u8::from(&e_ticket.validity_length),
validity_area_kind: ValidityAreaKind::from(&e_ticket.validity_area),
validity_area_value: FFIBuffer::from(e_ticket.validity_area),
validity_area_value: FFIByteBuffer::from(e_ticket.validity_area),
sale_datetime: e_ticket.sale_datetime.timestamp(),
sale_device_kind: SaleDeviceKind::from(&e_ticket.sale_device),
sale_device_value: u16::from(&e_ticket.sale_device),
Expand All @@ -220,18 +220,18 @@ impl FFIETicket {
period_pass_validity_area_kind: ValidityAreaKind::from(
&e_ticket.period_pass_validity_area,
),
period_pass_validity_area_value: FFIBuffer::from(e_ticket.period_pass_validity_area),
period_pass_validity_area_value: FFIByteBuffer::from(e_ticket.period_pass_validity_area),
extension_product_code_kind: ProductCodeKind::from(&e_ticket.extension_product_code),
extension_product_code_value: u16::from(&e_ticket.extension_product_code),
extension_1_validity_area_kind: ValidityAreaKind::from(
&e_ticket.extension_1_validity_area,
),
extension_1_validity_area_value: FFIBuffer::from(e_ticket.extension_1_validity_area),
extension_1_validity_area_value: FFIByteBuffer::from(e_ticket.extension_1_validity_area),
extension_1_fare_cents: e_ticket.extension_1_fare_cents,
extension_2_validity_area_kind: ValidityAreaKind::from(
&e_ticket.extension_2_validity_area,
),
extension_2_validity_area_value: FFIBuffer::from(e_ticket.extension_2_validity_area),
extension_2_validity_area_value: FFIByteBuffer::from(e_ticket.extension_2_validity_area),
extension_2_fare_cents: e_ticket.extension_2_fare_cents,
sale_status: e_ticket.sale_status,
validity_start_datetime: e_ticket.validity_start_datetime.timestamp(),
Expand Down Expand Up @@ -271,36 +271,36 @@ impl FFIHistory {
}
}

impl From<ValidityArea> for FFIBuffer<u8> {
impl From<ValidityArea> for FFIByteBuffer {
fn from(val: ValidityArea) -> Self {
match val {
ValidityArea::OldZone(zone_num) => {
let mut zone_nums_vec = vec![zone_num];
let ffi_buffer = FFIBuffer::from(&mut zone_nums_vec);
let ffi_buffer = FFIByteBuffer::from(&mut zone_nums_vec);
std::mem::forget(zone_nums_vec);
ffi_buffer
}
ValidityArea::Vehicle(vehicle_type) => {
let mut vehicle_nums_vec = vec![u8::from(&vehicle_type)];
let ffi_buffer = FFIBuffer::from(&mut vehicle_nums_vec);
let ffi_buffer = FFIByteBuffer::from(&mut vehicle_nums_vec);
std::mem::forget(vehicle_nums_vec);
ffi_buffer
}
ValidityArea::Zone(zones) => {
let mut zones_vec: Vec<u8> = zones.iter().map(u8::from).collect();
let ffi_buffer = FFIBuffer::from(&mut zones_vec);
let ffi_buffer = FFIByteBuffer::from(&mut zones_vec);
std::mem::forget(zones_vec);
ffi_buffer
}
}
}
}

impl From<Vec<History>> for FFIBuffer<FFIHistory> {
impl From<Vec<History>> for FFIHistoryBuffer {
fn from(val: Vec<History>) -> Self {
let mut ffi_histories: Vec<FFIHistory> =
val.iter().map(|x| FFIHistory::from_history(x)).collect();
let ffi_buffer = FFIBuffer::from(&mut ffi_histories);
let ffi_buffer = FFIHistoryBuffer::from(&mut ffi_histories);
std::mem::forget(ffi_histories);
ffi_buffer
}
Expand Down

0 comments on commit c0e6677

Please sign in to comment.