Skip to content
This repository was archived by the owner on Nov 16, 2024. It is now read-only.

Sergey/nanocom #3

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ members = [
"u144",
"u160",
"publish-ws",
"yagen"
"yagen",
"xpcom",
"xpcom/tool"
]
6 changes: 3 additions & 3 deletions publish-ws/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "publish-ws"
version = "0.1.9"
version = "0.1.10"
authors = ["natfoam"]
edition = "2021"
description = "Publish Workspace Packages"
Expand All @@ -11,5 +11,5 @@ repository = "https://github.com/natfoam/lib"

[dependencies]
toml = "0.5.9"
serde = "1.0.137"
serde_derive = "1.0.137"
serde = "1.0.138"
serde_derive = "1.0.138"
8 changes: 8 additions & 0 deletions xpcom/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "xpcom"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
130 changes: 130 additions & 0 deletions xpcom/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use std::{
ptr::null_mut,
sync::atomic::{AtomicU32, Ordering},
};

type HRESULT = u32;

const S_OK: HRESULT = 0;
const E_NOINTERFACE: HRESULT = 0x80004002;
const E_POINTER: HRESULT = 0x80004003;

type GUID = u128;

type ULONG = u32;

//

pub trait Interface: 'static {
const ID: GUID;
}

#[repr(transparent)]
pub struct Obj<I: Interface>(&'static Vmt<Obj<I>, I>);

#[allow(non_snake_case)]
#[repr(C)]
struct Vmt<T, I: Interface> {
QueryInterface:
extern "stdcall" fn(this: &mut T, riid: &GUID, ppvObject: *mut *mut T) -> HRESULT,
AddRef: extern "stdcall" fn(this: &mut T) -> ULONG,
Release: extern "stdcall" fn(this: &mut T) -> ULONG,
interface: I,
}

#[repr(transparent)]
pub struct Ref<I: Interface>(*mut Obj<I>);

impl<I: Interface> Ref<I> {
pub fn raw(&self) -> &mut Obj<I> {
unsafe { &mut *self.0 }
}
pub fn new(raw: &mut Obj<I>) -> Self {
(raw.0.AddRef)(raw);
Self(raw)
}
}

impl<I: Interface> Drop for Ref<I> {
fn drop(&mut self) {
let raw = self.raw();
(raw.0.Release)(raw);
}
}

impl<I: Interface> Clone for Ref<I> {
fn clone(&self) -> Self {
Self::new(self.raw())
}
}

//

pub trait Class: 'static + Sized {
type Interface: Interface;
const INTERFACE: Self::Interface;
}

#[repr(C)]
struct ClassObj<C: Class> {
vmt: Box<Vmt<Self, C::Interface>>,
counter: AtomicU32,
value: C,
}

impl<C: Class> ClassObj<C> {
fn new(value: C) -> Box<Self> {
Box::new(ClassObj {
vmt: Box::new(Vmt {
QueryInterface: ClassObj::QueryInterface,
AddRef: ClassObj::AddRef,
Release: ClassObj::Release,
interface: C::INTERFACE,
}),
counter: AtomicU32::default(),
value,
})
}
extern "stdcall" fn QueryInterface(
&mut self,
riid: &GUID,
ppvObject: *mut *mut Self,
) -> HRESULT {
if ppvObject == null_mut() {
return E_POINTER;
}
let result: (*mut Self, HRESULT) = if C::Interface::ID == *riid {
self.AddRef();
(self, S_OK)
} else {
(null_mut(), E_NOINTERFACE)
};
unsafe { *ppvObject = result.0 }
result.1
}
extern "stdcall" fn AddRef(&mut self) -> ULONG {
self.counter.fetch_add(1, Ordering::Relaxed) + 1
}
extern "stdcall" fn Release(&mut self) -> ULONG {
match self.counter.fetch_sub(1, Ordering::Relaxed) {
0 => panic!("release"),
1 => {
unsafe { Box::from_raw(self) };
0
}
c => c - 1,
}
}
}

pub fn new<C: Class>(value: C) -> Ref<C::Interface> {
let i = Box::into_raw(ClassObj::new(value)) as *mut Obj<C::Interface>;
Ref::new(unsafe { &mut *i })
}

#[cfg(test)]
mod tests {

#[test]
fn it_works() {}
}
12 changes: 12 additions & 0 deletions xpcom/tool/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "xpcom-tool"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = "1.0.138"
serde_derive = "1.0.138"
serde_json = "1.0.82"
serde_yaml = "0.8.24"
46 changes: 46 additions & 0 deletions xpcom/tool/src/guid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use serde::{
de::{Error, Visitor},
Deserialize, Serialize,
};

pub struct Guid(pub u128);

impl Serialize for Guid {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(format!("{:X}", self.0).as_str())
}
}

struct StringVisitor;

impl<'de> Visitor<'de> for StringVisitor {
type Value = String;

fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a string GUID")
}

fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: Error,
{
Ok(v)
}
}

impl<'de> Deserialize<'de> for Guid {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = deserializer.deserialize_string(StringVisitor)?;
let x = u128::from_str_radix(s.as_str(), 16);
match x {
Ok(v) => Ok(Guid(v)),
Err(e) => Err(D::Error::custom(e)),
}
}
}
19 changes: 19 additions & 0 deletions xpcom/tool/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
mod guid;
mod types;

use crate::types::{interface, method, param, ptr, struct_, Library, Type};

fn main() {
let library = Library::from([
struct_("S", &[param("begin", Type::U8)]),
interface(
"IMy",
0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF,
&[method("GetValue", &[], ptr(Type::U32))],
),
]);

// let x = serde_json::to_string(&library).unwrap();
let x = serde_yaml::to_string(&library).unwrap();
println!("{}", x);
}
79 changes: 79 additions & 0 deletions xpcom/tool/src/types/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use std::collections::HashMap;

use serde_derive::{Deserialize, Serialize};

use crate::guid::Guid;

#[derive(Serialize, Deserialize, Clone)]
pub enum Type {
I8,
U8,
I16,
U16,
I32,
U32,
I64,
U64,
Ptr(Box<Type>),
Id(String),
}

#[derive(Serialize, Deserialize, Clone)]
pub struct Param {
name: String,
r#type: Type,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct Method {
name: String,
params: Vec<Param>,
result: Type,
}

type Struct = Vec<Param>;

#[derive(Serialize, Deserialize)]
pub enum TypeDef {
Struct(Struct),
Interface { guid: Guid, methods: Vec<Method> },
}

fn type_def(name: &str, def: TypeDef) -> (String, TypeDef) {
(name.to_string(), def)
}

pub fn struct_(name: &str, params: &[Param]) -> (String, TypeDef) {
type_def(name, TypeDef::Struct(params.to_vec()))
}

pub fn interface(name: &str, guid: u128, methods: &[Method]) -> (String, TypeDef) {
type_def(
name,
TypeDef::Interface {
guid: Guid(guid),
methods: methods.to_vec(),
},
)
}

pub fn method(name: &str, params: &[Param], result: Type) -> Method {
Method {
name: name.to_string(),
params: params.to_vec(),
result,
}
}

pub fn ptr(type_: Type) -> Type {
Type::Ptr(Box::new(type_))
}

pub fn param(name: &str, type_: Type) -> Param {
Param {
name: name.to_string(),
r#type: type_,
}
}

pub type Library = HashMap<String, TypeDef>;