GitLab will be upgraded to the 12.10.14-ce.0 on 28 Sept 2020 at 2.00pm (AEDT) to 2.30pm (AEDT). During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to us at N110 (b) CSIT building.

Commit 67ba114c authored by Kunshan Wang's avatar Kunshan Wang

API-GEN: Testing the API...

Test whether the generated stubs are reasonable.
parent 913aed14
...@@ -2,6 +2,10 @@ RUSTC=rustc ...@@ -2,6 +2,10 @@ RUSTC=rustc
MUAPI_H_DIR=.. MUAPI_H_DIR=..
INCLUDE_DIR=$(MUAPI_H_DIR) INCLUDE_DIR=$(MUAPI_H_DIR)
.PHONY: all
all: cclient
rustpart.a: *.rs rustpart.a: *.rs
$(RUSTC) --crate-type=staticlib -o rustpart.a mock.rs $(RUSTC) --crate-type=staticlib -o rustpart.a mock.rs
......
#![allow(unused_variables)] // stubs #![allow(unused_variables)] // stubs
#![allow(dead_code)] // stubs #![allow(dead_code)] // stubs
/**
* This is a mock micro VM implementation. The purpose is to check whether the `api_c.rs` structs,
* the `api_bridge.rs` forwarder and the filler codes are correctly implemented (specifically,
* whether the parameters and the return values are correctly passed), and whether the
* auto-generated stubs are reasonable.
*
* This file can be used as a guideline for implementing the API. Some concerns are highlighted in
* the docstrings.
*/
use std::os::raw::*; use std::os::raw::*;
use std::ffi::CStr; use std::ffi::CStr;
use std::ffi::CString;
use std::collections::HashMap;
use api_c::*; use api_c::*;
use api_bridge::*; use api_bridge::*;
use deps::*; use deps::*;
/**
* NOTE: This could be one of the two top-level functions that are exposed to the client.
*
* Unlike the MuVM, MuCtx and MuIRBuilder structs, this function is not standardised. The reason is
* that in a production setting, the micro VM may not even be created by the client. For example,
* if we use boot-images, the micro VM exists since the beginning of the execution. The pointer to
* the MuVM struct may be held by a global (static) variable and can never be freed.
*
* If the micro VM implementation allows the client to create new micro VM instances as requested,
* it can provide functions that return the C-level `struct MuVM*` pointers, such as this one, and
* the `mu_refimpl2_new` and `mu_refimpl2_new_ex` functions found in the reference implementation.
*
* In this example, the micro VM instance is created on the heap, using Box. The C-visible struct
* is created by the `make_new_MuVM` function generated in `api_bridge`, which populates the
* method table and sets the "real" MuVM pointer as its header.
*/
#[no_mangle] #[no_mangle]
pub extern fn new_mock_micro_vm(name: CMuCString) -> *mut CMuVM { pub extern fn new_mock_micro_vm(name: CMuCString) -> *mut CMuVM {
println!("name: {:?}", name); println!("name: {:?}", name);
...@@ -17,9 +46,12 @@ pub extern fn new_mock_micro_vm(name: CMuCString) -> *mut CMuVM { ...@@ -17,9 +46,12 @@ pub extern fn new_mock_micro_vm(name: CMuCString) -> *mut CMuVM {
println!("The client asked to create a micro VM: {}", rust_name); println!("The client asked to create a micro VM: {}", rust_name);
// let mut muvm: Box<MuVM> = Default::default();
// muvm.my_name = rust_name;
let muvm = Box::new(MuVM { let muvm = Box::new(MuVM {
my_name: rust_name, my_name: rust_name,
contexts: Vec::new(), ..Default::default()
}); });
let muvm_ptr = Box::into_raw(muvm); let muvm_ptr = Box::into_raw(muvm);
...@@ -46,11 +78,32 @@ pub extern fn free_mock_micro_vm(cmvm: *mut CMuVM) { ...@@ -46,11 +78,32 @@ pub extern fn free_mock_micro_vm(cmvm: *mut CMuVM) {
println!("All structures re-boxed and ready for deallocation. By the way, is it really possible to destroy a micro VM in a productional setting?"); println!("All structures re-boxed and ready for deallocation. By the way, is it really possible to destroy a micro VM in a productional setting?");
} }
/**
* The micro VM itself.
*
* NOTE: If the "real" micro VM is implemented in a different place (such as `../VM.rs`), it could
* be defined as:
*
* ```rust
* pub type MuVM = vm.VM;
*
* // in vm.rs:
* impl VM {
* // copy the stubs here.
* }
* ```
*
* Neither the client nor the `api_bridge.rs` can tell which is the actual MuVM struct, because it
* is not exposed to C, and the `api_bridge.rs` forwarders never access any field in the high-level
* MuVM struct.
*/
#[derive(Default)]
pub struct MuVM { pub struct MuVM {
my_name: String, my_name: String,
contexts: Vec<MuCtx>, contexts: Vec<MuCtx>,
cname_dict: HashMap<MuID, CString>,
trap_handler: Option<CMuTrapHandler>,
trap_handler_user_data: Option<CMuCPtr>,
} }
pub struct MuCtx { pub struct MuCtx {
...@@ -67,19 +120,40 @@ impl MuVM { ...@@ -67,19 +120,40 @@ impl MuVM {
} }
pub fn id_of(&mut self, name: MuName) -> MuID { pub fn id_of(&mut self, name: MuName) -> MuID {
if name == "@truth" { if name == "@forty_two" {
42 42
} else { } else {
panic!("I don't know the id of it") panic!("I don't know the id of {}", name)
} }
} }
/**
* The client expects a "const char*" (expressed in the muapi.h as "char*", but "const char*"
* should be more appropriate). The client does not know when it should free that string, so
* the micro VM has to immortalise a CString object. In this example, the Rust-level MuVM
* struct holds a `cname_dict` hashmap which owns all CString instances.
*/
pub fn name_of(&mut self, id: MuID) -> CMuCString { pub fn name_of(&mut self, id: MuID) -> CMuCString {
panic!("Not implemented") let c_string = self.cname_dict.entry(id).or_insert_with(|| {
println!("Creating name for ID {}...", id);
let rust_string = format!("@mvm.id{}", id);
CString::new(rust_string).unwrap()
});
// Indeed the returned string is const, but the C API does not properly express the
// constness. Perhaps the C API can be improved without adding too much complexity.
c_string.as_ptr() as CMuCString
} }
pub fn set_trap_handler(&mut self, trap_handler: CMuTrapHandler, userdata: CMuCPtr) { pub fn set_trap_handler(&mut self, trap_handler: CMuTrapHandler, userdata: CMuCPtr) {
panic!("Not implemented") self.trap_handler = Some(trap_handler);
self.trap_handler_user_data = Some(userdata);
println!("Set the trap handler to {:?} and the userdata to {:?}", trap_handler, userdata);
println!("Let's call the trap handler now.");
// TODO: Call the trap handler to test it.
} }
} }
......
...@@ -9,6 +9,18 @@ int main() { ...@@ -9,6 +9,18 @@ int main() {
MuVM *mvm = new_mock_micro_vm("cclientt"); MuVM *mvm = new_mock_micro_vm("cclientt");
MuID forty_two = mvm->id_of(mvm, "@forty_two");
printf("forty_two = %d\n", forty_two);
MuName name_43 = mvm->name_of(mvm, 43);
printf("name_43 = '%s'\n", name_43);
MuName name_43_2 = mvm->name_of(mvm, 43);
printf("name_43_2 = '%s'\n", name_43_2);
// TODO: Register a trap handler to see if Rust can really call back.
free_mock_micro_vm(mvm); free_mock_micro_vm(mvm);
return 0; return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment