Saturday, November 16, 2019
Thursday, September 19, 2019
A bit research on String type in Rust
How did the String Type in Rust define?
There are two type of string types in Rust. Once is &str and other one is “String”.
String is heap allocated, grow able and not null termiated type.
&str is a slice(&[u8] ) that always points to a UTF8 valid sequence.
learn more about type usage here String types
But we are trying to focus on “String” type and how do we search Rust source code to see how this type is implemented.
String type - Heap allocation
Heap allocated memory implies that there will be pointer behind the definition of this type.
Let’s see,
We can get the rust source from below link.
https://doc.rust-lang.org/std/string/struct.String.html
click on the src button, as highlighted in the link.
it will directly take you to the surprising fact that String is simply a vector ( vec ).
String is a Vec<u8>
We know that Vec is also a heap allocated memory. In order to find how “vec” is defined in the source ,we need to search keyword “Vec” in the source code.
click on “src”
Interestingly, you will see the code.
pub struct Vec<T> {
buf: RawVec<T>,
len: usize,
}
I haven’t heard about RawVec earlier, but this is coming from : crate::raw_vec::RawVec;
raw-vec is implemeted for handling contiguous heap allocations.
Rawvec is implemented as below using a Unique pointer.
As guessed , we come to know that String type is actually using a pointer.
But what is unique pointer?
It comes from use core::ptr::Unique;
Unique is wapper around a raw non nullable ‘*mut T’.
interesting …
NonZero is wrapper type for raw pointers and integers that never becomes zero or null .
Tuesday, August 27, 2019
FFI tricks in Rust programming Language
How to do a trick on your Rust compiler to allow external (Foreign Language - FFI) functions
Rust is cool programming language which you can easily plugin to other languages ( Foreign Languages) .
Some of the FFI (Foreign language Interface) methods to call rust programs from C programming and Python programming languages are explained here.
Rust - Two things you should know for allowing Foreign language to call
#[no_mangle]
You might see lot of libraries using #[no_mangle] procedural macro.
The #[no_mangle] inform the Rust compiler that this is foreign language function and not to do anything weird with the symbols of this function when compiled because this will called from from other languages. This is needed if you plan on doing any FFI. Not doing so means you won’t be able to reference it in other languages.
extern
The extern keyword is used in two places in Rust. One is in conjunction with the crate keyword to make your Rust code aware of other Rust crates in your project, i.e. extern crate lazy static. The other use is in foreign function interfaces (FFI).
read more extern
how to create a shared object ie .so file from your Rust program ?
We can create a library in Rust using command below command
We are required to update the Cargo.toml
[dependencies]
[lib]
name = "callc"
crate-type = ["staticlib", "cdylib"]
cdylib is important crate type to specifiy in the Cargo.toml.
--crate-type=cdylib
, #[crate_type = "cdylib"]
- A dynamic system library will be produced. This is used when compiling a dynamic library to be loaded from another language. This output type will create *.so
files on Linux, *.dylib
files on macOS, and *.dll
files on Windows.
Read more on this here linkage
Cargo new callc
//lib.rs
#[no_mangle]
pub extern fn hello(){
println!("hello world inside rust ");
}
as we discussed earlier , since we use #[no_mangle], we can directly go ahead and compile it.
cargo build --release
How to check the generate .so file ?
A file with extension “.so” will generated in you target->release library.
run the below command to verify the function in the shared object.
$nm -D ‘filename.so’ | grep ‘function_name’
Our external function name is available in the shared object file created.
Create a C program for calling the shared object ( .so file)
create C program to call the hello function in your ‘src’ folder.
hello.c
#include<stdio.h>
#include "hello.h" /*header file to be included
/* the main C program to call the hello function
/* hello function is resides in the .so ( shared object) file
int main(void){
hello();
}
Below header file needs to be created in your ‘src’ folder
hello.h
/*the header include file should have the function declaration.
void hello();
We should link the .so file while compiling the c program. The below command will link and compile the program.
While compiling the C program, link the .so file the ‘release’ folder.
gcc -o hello hello.c -L. -Isrc /home/naveen/rustprojects/callc/target/release/libcallc.so
Your C program should get compiled and 'hello’e executable should be generated.
How do you call a Rust program from Python.
We are going to use the crate pyo3 for creating python modules.
create the projectfolder using cargo
cargo projectname --lib
Your Cargo.toml file should be updated as below in library and dependency sections.
[lib]
name = "string_sum"
crate_type = ["cdylib"]
[dependencies.pyo3]
version = "0.7.0"
features = ["extension-module"]
update the lib.rs with the below code:
use pyo3::prelude::*;
use pyo3::wrap_pyfunction;
#[pyfunction]
///format the 2 numbers as string
fn sum_as_string(x:usize,y:usize) -> PyResult<String>{
Ok((x+y).to_string())
}
#[pymodule]
fn string_sum(py:Python,m:&PyModule) -> PyResult<()>{
m.add_wrapped(wrap_pyfunction!(sum_as_string))?;
Ok(())
}
You can build the Rust program using Cargo build --release
This will create .so object in your cargo release folder. You might need to rename the file libstring_sum.so to string_sum.so
Now you can start import the module to the python interpreter and starting using the function string_sum
You might need to use python3 or 3+ interpreters for pyo3 to work.
As screenshot shows below , you can import the functions defined in the Rust module and use them in python.