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

Commit

Permalink
Merge pull request #105 from ballerina-platform/is_same_type
Browse files Browse the repository at this point in the history
Add support for Array Type Checker
  • Loading branch information
Kishanthan committed Mar 5, 2021
2 parents b90ed5b + 54770b1 commit 9fbebb6
Show file tree
Hide file tree
Showing 3 changed files with 236 additions and 2 deletions.
3 changes: 3 additions & 0 deletions runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ name = "ballerina_rt"
crate-type = ["cdylib"]

[dependencies]
num = "0.3"
num-traits = "0.2"
num-derive = "0.3"
14 changes: 12 additions & 2 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

// Rust Library

mod type_checker;

use std::ffi::CStr;
use std::mem;
use std::os::raw::c_char;
Expand All @@ -27,10 +29,18 @@ use std::slice;
mod bal_map;
pub use bal_map::map::BalMapInt;

// String comparision
// To check whether typecast is possible from source to destination
#[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;
assert!(!src_type.is_null());
assert!(!dest_type.is_null());
//Conversion to CStr
let source_cstr: &CStr = unsafe { CStr::from_ptr(src_type) };
let dest_cstr: &CStr = unsafe { CStr::from_ptr(dest_type) };
//Conversion to rust strings
let source: String = source_cstr.to_str().unwrap().to_owned();
let destination: String = dest_cstr.to_str().unwrap().to_owned();
return type_checker::same_type(source, destination);
}

// Prints 64 bit signed integer
Expand Down
221 changes: 221 additions & 0 deletions runtime/src/type_checker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
/*
* Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/

// Rust Library

extern crate num;
extern crate num_derive;

use crate::is_same_type;

use num::FromPrimitive;
use num_derive::FromPrimitive;
use std::ffi::CString;
use std::os::raw::c_char;

pub const BASE_TYPE_INDEX: usize = 0;
pub const ARRAY_MEMBER_TYPE_INDEX: usize = 1;
pub const ARRAY_SIZE_LSB_INDEX: usize = 2;
pub const ARRAY_SIZE_MSB_INDEX: usize = 3;

#[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,
}

// Compute total elements present in the data structure
pub fn compute_size(type_string: &str) -> i32 {
let mut hex_bits = String::new();
//Index 2 and 3 represent the size
hex_bits.push(type_string.chars().nth(ARRAY_SIZE_LSB_INDEX).unwrap());
hex_bits.push(type_string.chars().nth(ARRAY_SIZE_MSB_INDEX).unwrap());
let bits: std::result::Result<i32, std::num::ParseIntError> =
i32::from_str_radix(&hex_bits, 32);
let total_bits: i32 = bits.unwrap();
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 type_size(type_string: &str) -> i32 {
let type_char = type_string
.chars()
.nth(ARRAY_MEMBER_TYPE_INDEX)
.unwrap_or_else(|| panic!("Illegal type descriptor '{}', wrong length", type_string));
let bal_type = FromPrimitive::from_u32(type_char as u32).unwrap_or_else(|| {
panic!(
"Illegal type tag '{}' in type descriptor '{}'",
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)
}
}
}

/*
* To checking whether typecast is possible from source to destination
* Example of a type string - "AI041024"
* Index 0 - represents data structure
* Index 1 - represents type
* Index 2 and 3 - represents bits in hex followed by its size in decimal
*
* Algorithm -
* a. Convert null terminated string to rust string.
* b. Return true if type strings are same.
* c. Return false if data structure is different.
* d. Compute type size - type_size()
* e. Return false if source type size > destination type size
* g. Compute data structure length - compute_length()
*
* Data Structure Notations -
* A - Array
* M - Map
* */
#[no_mangle]
pub extern "C" fn same_type(source: String, destination: String) -> bool {
//If type strings are same
if source == destination {
return true;
}
//Index 0 represents type of data structure
if source.chars().nth(BASE_TYPE_INDEX) != destination.chars().nth(BASE_TYPE_INDEX) {
return false;
}
match source.chars().nth(BASE_TYPE_INDEX) {
Some('A') => {
if source.chars().nth(ARRAY_MEMBER_TYPE_INDEX)
!= destination.chars().nth(ARRAY_MEMBER_TYPE_INDEX)
{
let src_type_size: i32 = type_size(&source);
let dest_type_size: i32 = type_size(&destination);
if src_type_size > dest_type_size {
return false;
}
}
// Compute total number of elements present in the data structure
let src_size: i32 = compute_size(&source);
let dest_size: i32 = compute_size(&destination);
if src_size > dest_size {
return false;
}
}
_ => return false,
}
//If all the checks are passed, type cast from source to destination is valid
return true;
}

#[test]
fn src_type_size_less_than_dest() {
let src = CString::new("AF03122").unwrap();
let dest = CString::new("AX03122").unwrap();
assert_eq!(
is_same_type(
src.as_ptr() as *const c_char,
dest.as_ptr() as *const c_char
),
true
);
}

#[test]
fn src_type_size_greater_than_dest() {
let src = CString::new("AS03122").unwrap();
let dest = CString::new("AB03122").unwrap();
assert_eq!(
is_same_type(
src.as_ptr() as *const c_char,
dest.as_ptr() as *const c_char
),
false
);
}

#[test]
fn src_elements_less_than_dest() {
let src = CString::new("AB041023").unwrap();
let dest = CString::new("AX041024").unwrap();
assert_eq!(
is_same_type(
src.as_ptr() as *const c_char,
dest.as_ptr() as *const c_char
),
true
);
}

#[test]
fn src_elements_greater_than_dest() {
let src = CString::new("AB0519999").unwrap();
let dest = CString::new("AX03199").unwrap();
assert_eq!(
is_same_type(
src.as_ptr() as *const c_char,
dest.as_ptr() as *const c_char
),
false
);
}

#[test]
fn src_type_string_equal_to_dest() {
let src = CString::new("AF0599999").unwrap();
let dest = CString::new("AF0599999").unwrap();
assert_eq!(
is_same_type(
src.as_ptr() as *const c_char,
dest.as_ptr() as *const c_char
),
true
);
}

#[test]
fn map_test() {
let src = CString::new("MX0599999").unwrap();
let dest = CString::new("MF0599999").unwrap();
assert_eq!(
is_same_type(
src.as_ptr() as *const c_char,
dest.as_ptr() as *const c_char
),
false
);
}

0 comments on commit 9fbebb6

Please sign in to comment.