Skip to content
This repository has been archived by the owner on Nov 5, 2021. It is now read-only.

Add support for Array Type Checker #105

Merged
merged 8 commits into from
Mar 5, 2021
129 changes: 94 additions & 35 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,84 +19,143 @@

// Rust Library

use std::ffi::CStr;
use std::mem;
use std::os::raw::c_char;

// String comparision
pub fn compute_size(type_string: &str) -> i32 {
let mut bits = String::new();
//Index 2 and 3 represent the size
bits.push(type_string.chars().nth(2).unwrap());
bits.push(type_string.chars().nth(3).unwrap());
let total_bits: i32 = bits.parse().unwrap();
Copy link
Contributor

@ruvi-d ruvi-d Feb 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to handle unbounded Array sizes?

let mut length_bits = String::new();
let index = 4;
for i in 0..total_bits {
let iterator = i as usize;
length_bits.push(type_string.chars().nth(iterator + index).unwrap());
}
//Convert size to i32 for integer comparision
let size: i32 = length_bits.parse().unwrap();
return size;
}

pub fn calculate_type_priority(type_string: &str) -> i32 {
let mut priority = 0;
match type_string.chars().nth(1) {
Some('C') => priority = 4,
Some('B') => priority = 1,
Some('F') | Some('I') => priority = 8,
Some('A') => priority = 16,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a comment defining the char to type mapping?
#50 suggested X for any type

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Please check it!

_ => println!("Unsupported type"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return error Result for unsupported types

Copy link
Contributor Author

@shubhamnarlawar shubhamnarlawar Feb 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about this?

_ => panic!("Unsupported type in mangled string"),

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd return a std::result::Result from the function. The lib.rs side can check the return and panic if required.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}
return priority;
}

/*
* Algorithm for checking whether typecast is possible from source to destination
* Index 0 - represents data structure
* Index 1 - represents type
* Index 2 and 3 - represents bits followed by its size
* */
#[no_mangle]
pub extern "C" fn is_same_type(src_type : *const c_char, dest_type : *const c_char) -> bool
{
return src_type == dest_type;
pub extern "C" fn is_same_type(src_type: *const c_char, dest_type: *const c_char) -> bool {
//Conversion to CStr
let source_cstr: &CStr = unsafe { CStr::from_ptr(src_type) };
let dest_cstr: &CStr = unsafe { CStr::from_ptr(dest_type) };
Comment on lines +38 to +39
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an assert!(!src_type.is_null()); before CStr::from_ptr(src_type). Do for dest_type as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

//Conversion to rust strings
let source: String = source_cstr.to_str().unwrap().to_owned();
let destination: String = dest_cstr.to_str().unwrap().to_owned();
//If type strings are same
if source == destination {
return true;
}
//Index 0 represents type of data structure
if source.chars().nth(0) != destination.chars().nth(0) {
return false;
}
let mut src_priority = 0;
let mut dest_priority = 0;
match source.chars().nth(0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Define these magic numbers for bit positions as constants.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate a bit more in this suggestion?

Do you mean to use below snippet instead -

let constant = source.chars().nth(0);
match constant {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no.. I mean define the string indexes as constants like:

const BASE_TYPE_INDX: u32 = 0;
const ARRAY_MEMBER_TYPE_INDX: u32 = 1;
const ARRAY_SIZE_LSB_INDX: u32 = 2;
const ARRAY_SIZE_MSB_INDX: u32 = 3;
...
// Then use these constants when accessing the chars
match source.chars().nth(BASE_TYPE_INDX)

Hope that makes sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Makes sense. I have used usize instead of u32 as match expects a usize-

pub const BASE_TYPE_INDX: usize = 0;
pub const ARRAY_MEMBER_TYPE_INDX: usize = 1;
pub const ARRAY_SIZE_LSB_INDX: usize = 2;
pub const ARRAY_SIZE_MSB_INDX: usize = 3;

I will push this snippet along with other changes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It took some time, but I was able to come up with following code. Please do the research on rust language best practices in the future.

extern crate num;
extern crate num_derive;

use num::FromPrimitive;
use num_derive::FromPrimitive;

const ARRAY_MEMBER_TYPE_INDEX: usize = 2;

#[derive(Debug, PartialEq, FromPrimitive)]
#[repr(u32)]
enum BalType {
    Nil = 'N' as u32,
    Boolean = 'B' as u32,
    Int = 'I' as u32,
    Float = 'F' as u32,
    Decimal = 'D' as u32,
    String = 'S' as u32,
    Array = 'A' as u32,
    Any = 'X' as u32,
}

pub fn type_size(type_string: &str) -> i32 {
    let type_char = type_string.chars().nth(ARRAY_MEMBER_TYPE_INDEX)
                                      .unwrap_or_else(|| panic!("illegle type discripor '{}', wrong length", type_string));
    let bal_type = FromPrimitive::from_u32(type_char as u32)
                                      .unwrap_or_else(|| panic!("illegle type tag '{}' in type discripor '{}'", type_char, type_string));
    match bal_type {
        BalType::Boolean => { 1 }
        BalType::Int | BalType::Float => { 8 }
        BalType::String => { 12 }
        BalType::Any => { 16 }
        _ => { unimplemented!("type_size for '{:?}'", bal_type) }
    }
}

Cargo.toml

[dependencies]
num = "0.3"
num-traits = "0.2"
num-derive = "0.3"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the snippet! Sure. I will follow it in next tasks!

Let me modify other functions to follow above points!

Some('A') => {
if source.chars().nth(1) != destination.chars().nth(1) {
src_priority = calculate_type_priority(&source);
dest_priority = calculate_type_priority(&destination);
}
// If source type is bigger than destination, type cast is not possible
if src_priority > dest_priority {
return false;
}
let src_size: i32 = compute_size(&source);
let dest_size: i32 = compute_size(&destination);
if src_size > dest_size {
return false;
}
}
_ => println!("Unsupported data structure"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsupported should fail check. return false;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Done.

}
//If all the checks are passed, type cast from source to destination is valid
return true;
}

// Prints 64 bit signed integer
#[no_mangle]
pub extern "C" fn print64(num64 : i64)
{
println!("{}", num64);
pub extern "C" fn print64(num64: i64) {
println!("{}", num64);
}

// Prints 32 bit signed integer
#[no_mangle]
pub extern "C" fn print32(num32 : i32)
{
println!("{}", num32);
pub extern "C" fn print32(num32: i32) {
println!("{}", num32);
}

// Prints 16 bit signed integer
#[no_mangle]
pub extern "C" fn print16(num16 : i16)
{
println!("{}", num16);
pub extern "C" fn print16(num16: i16) {
println!("{}", num16);
}

// Prints 8 bit signed integer
#[no_mangle]
pub extern "C" fn print8(num8 : i8)
{
println!("{}", num8);
pub extern "C" fn print8(num8: i8) {
println!("{}", num8);
}

// Prints 64 bit unsigned integer
#[no_mangle]
pub extern "C" fn printu64(num64 : u64)
{
println!("{}", num64);
pub extern "C" fn printu64(num64: u64) {
println!("{}", num64);
}

// Prints 32 bit unsigned integer
#[no_mangle]
pub extern "C" fn printu32(num32 : u32)
{
println!("{}", num32);
pub extern "C" fn printu32(num32: u32) {
println!("{}", num32);
}

// Prints 16 bit unsigned integer
#[no_mangle]
pub extern "C" fn printu16(num16 : u16)
{
println!("{}", num16);
pub extern "C" fn printu16(num16: u16) {
println!("{}", num16);
}

// Prints 8 bit unsigned integer
#[no_mangle]
pub extern "C" fn printu8(num8 : u8)
{
println!("{}", num8);
pub extern "C" fn printu8(num8: u8) {
println!("{}", num8);
}

// Prints 64 bit float
#[no_mangle]
pub extern "C" fn printf64(num64 : f64)
{
println!("{}", num64);
pub extern "C" fn printf64(num64: f64) {
println!("{}", num64);
}

// Prints 32 bit float
#[no_mangle]
pub extern "C" fn printf32(num32 : f32)
{
println!("{}", num32);
pub extern "C" fn printf32(num32: f32) {
println!("{}", num32);
}

#[no_mangle]
Expand Down Expand Up @@ -125,7 +184,7 @@ pub extern "C" fn int_array_store(arr_ptr: *mut Vec<*mut i32>, n: i32, ref_ptr:

#[no_mangle]
pub extern "C" fn int_array_load(arr_ptr: *mut Vec<*mut i32>, n: i32) -> *mut i32 {
let arr = unsafe { Box::from_raw(arr_ptr)};
let arr = unsafe { Box::from_raw(arr_ptr) };
let n_size = n as usize;
let return_val = arr[n_size];
mem::forget(arr);
Expand Down