Skip to content

Commit

Permalink
Improve rs_port stage 4
Browse files Browse the repository at this point in the history
  • Loading branch information
devraymondsh committed Apr 18, 2023
1 parent 1168467 commit a8b252a
Show file tree
Hide file tree
Showing 36 changed files with 2,089 additions and 1,472 deletions.
17 changes: 8 additions & 9 deletions source/ports/rs_port/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
[package]
name = "metacall"
version = "0.3.1"
repository = "https://github.com/metacall/core/tree/develop/source/ports/rs_port"
authors = ["Vicente Eduardo Ferrer Garcia <vic798@gmail.com>", "Swarnim Arun <swarnimarun11@gmail.com>"]
authors = ["Mahdi Sharifi <devraymondsh@gmail.com>", "Vicente Eduardo Ferrer Garcia <vic798@gmail.com>", "Swarnim Arun <swarnimarun11@gmail.com>"]
description = "Call NodeJS, TypeScript, Python, C#, Ruby... functions from Rust (a Rust Port for MetaCall)."
edition = "2021"
keywords = ["programming-language", "ffi", "polyglot", "metacall", "function-mesh", "inter-language", "polyglot-programming"]
license = "Apache-2.0"
name = "metacall"
readme = "README.md"
description = "Call NodeJS, TypeScript, Python, C#, Ruby... functions from Rust (a Rust Port for MetaCall)."
repository = "https://github.com/metacall/core/tree/develop/source/ports/rs_port"
version = "0.4.0"

[lib]
name = "metacall"
crate-type = ["lib"] # TODO: Once this is unified with the loader, we should use cdylib type
crate-type = ["lib"]
path = "src/lib.rs"
edition = "2021"

[dependencies]
concat-idents = "1.1.4"
dyn-clone = "1.0.11"
metacall-inline = { path = "./inline", version = "0.1.1" }
metacall-inline = { path = "./inline", version = "0.2.0" }

[build-dependencies]
bindgen = { version = "0.64.0", default-features = false, features = ["runtime", "logging", "which-rustfmt"]}
59 changes: 27 additions & 32 deletions source/ports/rs_port/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,39 +1,34 @@
# docker build -t metacall/rs-port .
# docker run --rm -it metacall/rs-port

FROM metacall/core:dev AS develop
FROM devraymondsh/ubuntu-docker-rust

# Install dependencies
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
clang-11 clang-format-11 libclang-11-dev libtcc-dev valgrind libdw-dev libbfd-dev libdwarf-dev libffi-dev \
&& curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y \
&& . "/root/.cargo/env" \
&& rustup component add rustfmt \
&& rustup toolchain add nightly \
&& rustup component add clippy

ENV PATH="${PATH}:/root/.cargo/bin"
&& apt-get install -y --no-install-recommends build-essential cmake ca-certificates git nodejs npm pkg-config clang-11 clang-format-11 libclang-11-dev libtcc-dev cmake valgrind libdw-dev libbfd-dev libdwarf-dev libffi-dev python3 libpython3-dev python3-pip
RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 10

RUN cd build \
&& cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DOPTION_BUILD_DETOURS=Off \
-DOPTION_BUILD_EXAMPLES=Off \
-DOPTION_BUILD_LOADERS_C=On \
-DOPTION_BUILD_LOADERS_NODE=On \
-DOPTION_BUILD_LOADERS_PY=On \
-DOPTION_BUILD_LOADERS_TS=On \
-DOPTION_BUILD_SCRIPTS=Off \
-DOPTION_BUILD_SERIALS_RAPID_JSON=On \
-DOPTION_BUILD_TESTS=Off \
.. \
&& cmake --build . --target install \
&& cd /usr/local/lib \
&& ldconfig
WORKDIR /root/metacall-polyglot
RUN git clone https://github.com/metacall/core
RUN mkdir core/build

WORKDIR /usr/local/metacall/source/ports/rs_port
WORKDIR /root/metacall-polyglot/core/build
RUN cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DOPTION_BUILD_DETOURS=Off \
-DOPTION_BUILD_EXAMPLES=Off \
-DOPTION_BUILD_LOADERS_C=On \
-DOPTION_BUILD_LOADERS_NODE=On \
-DOPTION_BUILD_LOADERS_PY=On \
-DOPTION_BUILD_LOADERS_TS=On \
-DOPTION_BUILD_SCRIPTS=Off \
-DOPTION_BUILD_SERIALS_RAPID_JSON=On \
-DOPTION_BUILD_TESTS=Off \
..
RUN cmake --build . --target install
RUN cd /usr/local/lib && ldconfig

COPY . .
RUN rustup component add rustfmt
RUN rustup toolchain add nightly
RUN rustup component add clippy
RUN cargo install cargo-valgrind

CMD ["cargo", "test"]
WORKDIR /root/metacall-polyglot
CMD ["cargo", "test"]
16 changes: 9 additions & 7 deletions source/ports/rs_port/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,18 @@ export function sum(a: number, b: number): number {

`main.rs`
``` rust
use metacall::{hooks, loaders, structs::Any, metacall};
use metacall::{hooks, metacall, loaders};

fn main() {
// Metacall automatically shuts down when it goes out of scope
let _ = hooks::initialize().unwrap();
// Initialize Metacall at the top
let _metacall = hooks::initialize().unwrap();

// Load the file
loaders::from_single_file("ts", "sum.ts").unwrap();

loaders::from_file("ts", "sum.ts").unwrap();
// Call the sum function
let sum = metacall::<f64>("sum", [1.0, 2.0]).unwrap();

let sum = metacall("sum", [Any::Double(1.0), Any::Double(2.0)]).unwrap();

println!("sum: {:?}", sum);
assert_eq!(sum, 3.0);
}
```
2 changes: 1 addition & 1 deletion source/ports/rs_port/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn generate_bindings(headers: &[&str]) {

fn main() {
// When running from CMake
if let Ok(_) = env::var("CMAKE_BINDGEN") {
if env::var("CMAKE_BINDGEN").is_ok() {
const HEADERS: [&str; 3] = [
"include/metacall/metacall.h",
"include/metacall/metacall_value.h",
Expand Down
2 changes: 1 addition & 1 deletion source/ports/rs_port/inline/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "metacall-inline"
version = "0.1.1"
version = "0.2.0"
repository = "https://github.com/metacall/core/tree/develop/source/ports/rs_port"
edition = "2021"
license = "Apache-2.0"
Expand Down
115 changes: 115 additions & 0 deletions source/ports/rs_port/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use crate::types::MetacallValue;
use std::any::Any;

pub trait MetacallDowncast: Any {
fn into_any(self: Box<Self>) -> Box<dyn Any>;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl<T: Any> MetacallDowncast for T {
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl dyn MetacallValue {
/// Checks if the trait object is having the given type.
pub fn is<T: MetacallValue>(&self) -> bool {
MetacallDowncast::as_any(self).is::<T>()
}

/// Downcasts the inner value of the trait object and returns the ownership.
pub fn downcast<T: MetacallValue>(self: Box<Self>) -> Result<T, Box<Self>> {
if self.is::<T>() {
Ok(*MetacallDowncast::into_any(self).downcast::<T>().unwrap())
} else {
Err(self)
}
}

/// Downcasts the inner value of the trait object and returns a reference.
pub fn downcast_ref<T: MetacallValue>(&self) -> Option<&T> {
MetacallDowncast::as_any(self).downcast_ref::<T>()
}

/// Downcasts the inner value of the trait object and returns a mutable reference.
pub fn downcast_mut<T: MetacallValue>(&mut self) -> Option<&mut T> {
MetacallDowncast::as_any_mut(self).downcast_mut::<T>()
}
}

pub trait MetacallSealed {}
impl<T: Clone> MetacallSealed for T {}
impl MetacallSealed for str {}
impl<T: Clone> MetacallSealed for [T] {}

pub fn clone_box<T>(t: &T) -> Box<T>
where
T: ?Sized + MetacallClone,
{
unsafe {
let mut fat_ptr = t as *const T;
let data_ptr = &mut fat_ptr as *mut *const T as *mut *mut ();

assert_eq!(*data_ptr as *const (), t as *const T as *const ());

*data_ptr = <T as MetacallClone>::clone_box(t);

Box::from_raw(fat_ptr as *mut T)
}
}

pub trait MetacallClone: MetacallSealed {
fn clone_box(&self) -> *mut ();
}
impl<T> MetacallClone for T
where
T: Clone,
{
fn clone_box(&self) -> *mut () {
Box::<T>::into_raw(Box::new(self.clone())) as *mut ()
}
}

impl MetacallClone for str {
fn clone_box(&self) -> *mut () {
Box::<str>::into_raw(Box::from(self)) as *mut ()
}
}
impl<T> MetacallClone for [T]
where
T: Clone,
{
fn clone_box(&self) -> *mut () {
Box::<[T]>::into_raw(self.iter().cloned().collect()) as *mut ()
}
}
impl<'c> Clone for Box<dyn MetacallValue + 'c> {
fn clone(&self) -> Self {
clone_box(&**self)
}
}
impl<'c> Clone for Box<dyn MetacallValue + Send + 'c> {
fn clone(&self) -> Self {
clone_box(&**self)
}
}
impl<'c> Clone for Box<dyn MetacallValue + Sync + 'c> {
fn clone(&self) -> Self {
clone_box(&**self)
}
}
impl<'c> Clone for Box<dyn MetacallValue + Send + Sync + 'c> {
fn clone(&self) -> Self {
clone_box(&**self)
}
}

pub fn metacall_implementer_to_traitobj(v: impl MetacallValue) -> Box<dyn MetacallValue> {
Box::new(v) as Box<dyn MetacallValue>
}
11 changes: 10 additions & 1 deletion source/ports/rs_port/src/hooks.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
bindings::{metacall_destroy, metacall_initialize},
prelude::MetacallInitError,
types::MetacallInitError,
};
use std::ffi::c_int;

Expand All @@ -18,6 +18,15 @@ impl Drop for MetacallAutoDestroy {
}
}

/// Initializes Metacall. Always remember to store the output in a variable to avoid instant drop.
/// For example: ...
/// ```
/// // Initialize metacall at the top of your main function before loading your codes or
/// // calling any function.
/// let _metacall = metacall::initialize().unwrap();
///
///
/// ```
pub fn initialize() -> Result<MetacallAutoDestroy, MetacallInitError> {
if initialize_manually() != 0 {
return Err(MetacallInitError::new());
Expand Down
89 changes: 84 additions & 5 deletions source/ports/rs_port/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#![warn(clippy::all)]
#![allow(clippy::not_unsafe_ptr_arg_deref, clippy::boxed_local)]
#![allow(
clippy::not_unsafe_ptr_arg_deref,
clippy::boxed_local,
clippy::tabs_in_doc_comments,
clippy::needless_doctest_main
)]
/*
* MetaCall Library by Parra Studios
* A library for providing a foreign function interface calls.
Expand All @@ -20,19 +25,93 @@
*
*/

pub mod hooks;
pub mod loaders;
pub(crate) mod macros;
//! [METACALL](https://github.com/metacall/core) is a library that allows calling functions,
//! methods or procedures between programming languages. With METACALL you can transparently
//! execute code from / to any programming language, for example, call TypeScript code from Rust.
//! Click [here](https://github.com/metacall/install) for installation guide.
//!
//! General usage example:
//! Let's consider we have the following Typescript code:
//! `sum.ts`
//! ``` javascript
//! export function sum(a: number, b: number): number {
//! return a + b;
//! }
//! ```
//! Now let's jump into Rust:
//!
//! ```
//! use metacall::{hooks, metacall, loaders};
//!
//! fn main() {
//! // Initialize Metacall at the top
//! let _metacall = hooks::initialize().unwrap();
//!
//! // Load the file (Checkout the loaders module for loading multiple files
//! // or loading from string)
//! loaders::from_single_file("ts", "sum.ts").unwrap();
//!
//! // Call the sum function (Also checkout other metacall functions)
//! let sum = metacall::<f64>("sum", [1.0, 2.0]).unwrap();
//!
//! assert_eq!(sum, 3.0);
//! }
//!
//! ```
pub(crate) mod helpers;
pub(crate) mod parsers;
pub mod prelude;
pub(crate) use macros::private_macros::*;

/// Contains Metacall loaders from file and memory. Usage example: ...
/// ```
/// // Loading a single file with Nodejs.
/// metacall::loaders::from_single_file("node", "index.js").unwrap();
///
/// // Loading multiple files with Nodejs.
/// metacall::loaders::from_file("node", ["index.js", "main.js"]).unwrap();
///
/// // Loading a string with Nodejs.
/// let script = "function greet() { return 'hi there!' }; module.exports = { greet };";
/// metacall::loaders::from_memory("node", script).unwrap();
/// ```
pub mod loaders;

mod types;
pub use hooks::initialize;

#[doc(hidden)]
pub mod macros;

#[doc(hidden)]
pub mod hooks;
pub use types::*;

#[path = "metacall.rs"]
mod metacall_mod;
pub use metacall_mod::*;

/// Contains Metacall language inliners. Usage example: ...
/// ```
/// // Python
/// py! {
/// print("hello world")
/// }
///
/// // Nodejs
/// node! {
/// console.log("hello world");
/// }
///
/// // Typescript
/// ts! {
/// console.log("hello world");
/// }
/// ```
pub mod inline {
pub use metacall_inline::*;
}

#[allow(warnings)]
#[doc(hidden)]
pub mod bindings;
Loading

0 comments on commit a8b252a

Please sign in to comment.