From 234dd1b7a2678977ab70e12bc22d855bba76b59f Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Mon, 4 Jul 2022 20:08:05 -0700 Subject: [PATCH 01/15] structured. --- Cargo.toml | 3 ++- publish-ws/Cargo.toml | 4 +-- xpcom/Cargo.toml | 12 +++++++++ xpcom/src/main.rs | 63 +++++++++++++++++++++++++++++++++++++++++++ xpcom/src/x.yaml | 9 +++++++ 5 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 xpcom/Cargo.toml create mode 100644 xpcom/src/main.rs create mode 100644 xpcom/src/x.yaml diff --git a/Cargo.toml b/Cargo.toml index 12f86fb..2cf631a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,6 @@ members = [ "u144", "u160", "publish-ws", - "yagen" + "yagen", + "xpcom" ] diff --git a/publish-ws/Cargo.toml b/publish-ws/Cargo.toml index a2184b6..30b28f3 100644 --- a/publish-ws/Cargo.toml +++ b/publish-ws/Cargo.toml @@ -11,5 +11,5 @@ repository = "https://github.com/natfoam/lib" [dependencies] toml = "0.5.9" -serde = "1.0.137" -serde_derive = "1.0.137" \ No newline at end of file +serde = "1.0.138" +serde_derive = "1.0.138" \ No newline at end of file diff --git a/xpcom/Cargo.toml b/xpcom/Cargo.toml new file mode 100644 index 0000000..f51e1ab --- /dev/null +++ b/xpcom/Cargo.toml @@ -0,0 +1,12 @@ +[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] +serde = "1.0.138" +serde_derive = "1.0.138" +serde_json = "1.0.82" +serde_yaml = "0.8.24" diff --git a/xpcom/src/main.rs b/xpcom/src/main.rs new file mode 100644 index 0000000..7f75a82 --- /dev/null +++ b/xpcom/src/main.rs @@ -0,0 +1,63 @@ +use std::collections::HashMap; + +use serde_derive::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +enum Type { + I8, + U8, + I16, + U16, + I32, + U32, + I64, + U64, + Ptr(Box), + Id(String), +} + +#[derive(Serialize, Deserialize)] +struct Param { + name: String, + r#type: Type, +} + +#[derive(Serialize, Deserialize)] +struct Method { + name: String, + params: Vec, + result: Type, +} + +type Struct = Vec; + +#[derive(Serialize, Deserialize)] +enum TypeDef { + Struct(Struct), + Interface { guid: String, methods: Vec }, +} + +type Library = HashMap; + +fn main() { + let library = Library::from([ + ("S".to_string(), TypeDef::Struct(vec![ + Param { name: "begin".to_string(), r#type: Type::U8 }, + ])), + ( + "IMy".to_string(), + TypeDef::Interface { + guid: "".to_string(), + methods: vec![Method { + name: "GetValue".to_string(), + params: vec![], + result: Type::Ptr(Box::new(Type::U32)), + }], + }, + ), + ]); + + // let x = serde_json::to_string(&library).unwrap(); + let x = serde_yaml::to_string(&library).unwrap(); + println!("{}", x); +} diff --git a/xpcom/src/x.yaml b/xpcom/src/x.yaml new file mode 100644 index 0000000..cf67b13 --- /dev/null +++ b/xpcom/src/x.yaml @@ -0,0 +1,9 @@ +--- +IMy: + Interface: + - "" + - - - GetValue + - [] + - Ptr: U32 +S: + Struct: [] \ No newline at end of file From 81ac52482020a016fe7340e96cf4240c93b01751 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Tue, 5 Jul 2022 10:16:51 -0700 Subject: [PATCH 02/15] Type --- publish-ws/Cargo.toml | 2 +- xpcom/src/main.rs | 57 ++++++++++++++++++++++++++++++++++++++----- xpcom/src/x.yaml | 9 ------- 3 files changed, 52 insertions(+), 16 deletions(-) delete mode 100644 xpcom/src/x.yaml diff --git a/publish-ws/Cargo.toml b/publish-ws/Cargo.toml index 30b28f3..7f8afb2 100644 --- a/publish-ws/Cargo.toml +++ b/publish-ws/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "publish-ws" -version = "0.1.9" +version = "0.1.10" authors = ["natfoam"] edition = "2021" description = "Publish Workspace Packages" diff --git a/xpcom/src/main.rs b/xpcom/src/main.rs index 7f75a82..86928af 100644 --- a/xpcom/src/main.rs +++ b/xpcom/src/main.rs @@ -1,6 +1,8 @@ -use std::collections::HashMap; +use std::{collections::HashMap, fmt::format}; +use serde::{Serialize, Deserialize, de::Visitor}; use serde_derive::{Deserialize, Serialize}; +use serde::de::Error; #[derive(Serialize, Deserialize)] enum Type { @@ -31,23 +33,66 @@ struct Method { type Struct = Vec; +struct Guid (u128); + +impl Serialize for Guid { + fn serialize(&self, serializer: S) -> Result + 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(self, v: String) -> Result + where + E: Error, { + Ok(v) + } +} + +impl<'de> Deserialize<'de> for Guid { + fn deserialize(deserializer: D) -> Result + 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(e).map_err(D::Error::custom) + } + } +} + #[derive(Serialize, Deserialize)] enum TypeDef { Struct(Struct), - Interface { guid: String, methods: Vec }, + Interface { guid: Guid, methods: Vec }, } type Library = HashMap; fn main() { let library = Library::from([ - ("S".to_string(), TypeDef::Struct(vec![ - Param { name: "begin".to_string(), r#type: Type::U8 }, - ])), + ( + "S".to_string(), + TypeDef::Struct(vec![Param { + name: "begin".to_string(), + r#type: Type::U8, + }]), + ), ( "IMy".to_string(), TypeDef::Interface { - guid: "".to_string(), + guid: Guid(0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF), methods: vec![Method { name: "GetValue".to_string(), params: vec![], diff --git a/xpcom/src/x.yaml b/xpcom/src/x.yaml deleted file mode 100644 index cf67b13..0000000 --- a/xpcom/src/x.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -IMy: - Interface: - - "" - - - - GetValue - - [] - - Ptr: U32 -S: - Struct: [] \ No newline at end of file From fa143cd52539e88f0fc5c95ebab85d1954ddb42f Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Tue, 5 Jul 2022 10:17:11 -0700 Subject: [PATCH 03/15] hashmap --- xpcom/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xpcom/src/main.rs b/xpcom/src/main.rs index 86928af..e06abb9 100644 --- a/xpcom/src/main.rs +++ b/xpcom/src/main.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, fmt::format}; +use std::collections::HashMap; use serde::{Serialize, Deserialize, de::Visitor}; use serde_derive::{Deserialize, Serialize}; From 4eae73774ebce06d4651a542e9f32f3fd0505559 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Tue, 5 Jul 2022 10:58:39 -0700 Subject: [PATCH 04/15] utilities --- xpcom/src/guid.rs | 46 +++++++++++++++++++++++ xpcom/src/main.rs | 96 ++++++++++++++++++++--------------------------- 2 files changed, 87 insertions(+), 55 deletions(-) create mode 100644 xpcom/src/guid.rs diff --git a/xpcom/src/guid.rs b/xpcom/src/guid.rs new file mode 100644 index 0000000..52c4ef3 --- /dev/null +++ b/xpcom/src/guid.rs @@ -0,0 +1,46 @@ +use serde::{ + de::{Error, Visitor}, + Deserialize, Serialize, +}; + +pub struct Guid(pub u128); + +impl Serialize for Guid { + fn serialize(&self, serializer: S) -> Result + 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(self, v: String) -> Result + where + E: Error, + { + Ok(v) + } +} + +impl<'de> Deserialize<'de> for Guid { + fn deserialize(deserializer: D) -> Result + 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)), + } + } +} diff --git a/xpcom/src/main.rs b/xpcom/src/main.rs index e06abb9..a65b437 100644 --- a/xpcom/src/main.rs +++ b/xpcom/src/main.rs @@ -1,10 +1,10 @@ -use std::collections::HashMap; +mod guid; -use serde::{Serialize, Deserialize, de::Visitor}; +use guid::Guid; use serde_derive::{Deserialize, Serialize}; -use serde::de::Error; +use std::collections::HashMap; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone)] enum Type { I8, U8, @@ -18,13 +18,13 @@ enum Type { Id(String), } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone)] struct Param { name: String, r#type: Type, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone)] struct Method { name: String, params: Vec, @@ -33,72 +33,58 @@ struct Method { type Struct = Vec; -struct Guid (u128); - -impl Serialize for Guid { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer { - serializer.serialize_str(format!("{:X}", self.0).as_str()) - } +#[derive(Serialize, Deserialize)] +enum TypeDef { + Struct(Struct), + Interface { guid: Guid, methods: Vec }, } -struct StringVisitor; +fn type_def(name: &str, def: TypeDef) -> (String, TypeDef) { + (name.to_string(), def) +} -impl<'de> Visitor<'de> for StringVisitor { - type Value = String; +fn struct_(name: &str, params: &[Param]) -> (String, TypeDef) { + type_def(name, TypeDef::Struct(params.to_vec())) +} - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("a string GUID") - } +fn interface(name: &str, guid: u128, methods: &[Method]) -> (String, TypeDef) { + type_def( + name, + TypeDef::Interface { + guid: Guid(guid), + methods: methods.to_vec(), + }, + ) +} - fn visit_string(self, v: String) -> Result - where - E: Error, { - Ok(v) +fn method(name: &str, params: &[Param], result: Type) -> Method { + Method { + name: name.to_string(), + params: params.to_vec(), + result, } } -impl<'de> Deserialize<'de> for Guid { - fn deserialize(deserializer: D) -> Result - 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(e).map_err(D::Error::custom) - } - } +fn ptr(t: Type) -> Type { + Type::Ptr(Box::new(t)) } -#[derive(Serialize, Deserialize)] -enum TypeDef { - Struct(Struct), - Interface { guid: Guid, methods: Vec }, +fn param(name: &str, t: Type) -> Param { + Param { name: name.to_string(), r#type: t } } type Library = HashMap; fn main() { let library = Library::from([ - ( - "S".to_string(), - TypeDef::Struct(vec![Param { - name: "begin".to_string(), - r#type: Type::U8, - }]), + struct_( + "S", + &[param("begin",Type::U8)], ), - ( - "IMy".to_string(), - TypeDef::Interface { - guid: Guid(0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF), - methods: vec![Method { - name: "GetValue".to_string(), - params: vec![], - result: Type::Ptr(Box::new(Type::U32)), - }], - }, + interface( + "IMy", + 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF, + &[method("GetValue", &[], ptr(Type::U32))], ), ]); From e689c1ce4e365da5f2e3ffa407fa4b714ca328cb Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Tue, 5 Jul 2022 10:59:50 -0700 Subject: [PATCH 05/15] main --- xpcom/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xpcom/src/main.rs b/xpcom/src/main.rs index a65b437..8585e03 100644 --- a/xpcom/src/main.rs +++ b/xpcom/src/main.rs @@ -65,12 +65,12 @@ fn method(name: &str, params: &[Param], result: Type) -> Method { } } -fn ptr(t: Type) -> Type { - Type::Ptr(Box::new(t)) +fn ptr(type_: Type) -> Type { + Type::Ptr(Box::new(type_)) } -fn param(name: &str, t: Type) -> Param { - Param { name: name.to_string(), r#type: t } +fn param(name: &str, type_: Type) -> Param { + Param { name: name.to_string(), r#type: type_ } } type Library = HashMap; From 967fca88aaf282644d2078bc81b47c9a3cd6e077 Mon Sep 17 00:00:00 2001 From: sergey-shandar Date: Tue, 5 Jul 2022 15:54:55 -0700 Subject: [PATCH 06/15] main mod --- xpcom/src/main.rs | 81 ++---------------------------------------- xpcom/src/types/mod.rs | 79 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 78 deletions(-) create mode 100644 xpcom/src/types/mod.rs diff --git a/xpcom/src/main.rs b/xpcom/src/main.rs index 8585e03..2000c22 100644 --- a/xpcom/src/main.rs +++ b/xpcom/src/main.rs @@ -1,86 +1,11 @@ mod guid; +mod types; -use guid::Guid; -use serde_derive::{Deserialize, Serialize}; -use std::collections::HashMap; - -#[derive(Serialize, Deserialize, Clone)] -enum Type { - I8, - U8, - I16, - U16, - I32, - U32, - I64, - U64, - Ptr(Box), - Id(String), -} - -#[derive(Serialize, Deserialize, Clone)] -struct Param { - name: String, - r#type: Type, -} - -#[derive(Serialize, Deserialize, Clone)] -struct Method { - name: String, - params: Vec, - result: Type, -} - -type Struct = Vec; - -#[derive(Serialize, Deserialize)] -enum TypeDef { - Struct(Struct), - Interface { guid: Guid, methods: Vec }, -} - -fn type_def(name: &str, def: TypeDef) -> (String, TypeDef) { - (name.to_string(), def) -} - -fn struct_(name: &str, params: &[Param]) -> (String, TypeDef) { - type_def(name, TypeDef::Struct(params.to_vec())) -} - -fn interface(name: &str, guid: u128, methods: &[Method]) -> (String, TypeDef) { - type_def( - name, - TypeDef::Interface { - guid: Guid(guid), - methods: methods.to_vec(), - }, - ) -} - -fn method(name: &str, params: &[Param], result: Type) -> Method { - Method { - name: name.to_string(), - params: params.to_vec(), - result, - } -} - -fn ptr(type_: Type) -> Type { - Type::Ptr(Box::new(type_)) -} - -fn param(name: &str, type_: Type) -> Param { - Param { name: name.to_string(), r#type: type_ } -} - -type Library = HashMap; +use crate::types::{interface, method, param, ptr, struct_, Library, Type}; fn main() { let library = Library::from([ - struct_( - "S", - &[param("begin",Type::U8)], - ), + struct_("S", &[param("begin", Type::U8)]), interface( "IMy", 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF, diff --git a/xpcom/src/types/mod.rs b/xpcom/src/types/mod.rs new file mode 100644 index 0000000..d9c2312 --- /dev/null +++ b/xpcom/src/types/mod.rs @@ -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), + 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, + result: Type, +} + +type Struct = Vec; + +#[derive(Serialize, Deserialize)] +pub enum TypeDef { + Struct(Struct), + Interface { guid: Guid, methods: Vec }, +} + +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; From 87f7cb548970a4aff8c7c00c0303b1f916b7f300 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Wed, 6 Jul 2022 19:55:29 -0700 Subject: [PATCH 07/15] XPCOM library --- Cargo.toml | 3 ++- xpcom/Cargo.toml | 4 ---- xpcom/src/lib.rs | 8 ++++++++ xpcom/tool/Cargo.toml | 12 ++++++++++++ xpcom/{ => tool}/src/guid.rs | 0 xpcom/{ => tool}/src/main.rs | 0 xpcom/{ => tool}/src/types/mod.rs | 0 7 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 xpcom/src/lib.rs create mode 100644 xpcom/tool/Cargo.toml rename xpcom/{ => tool}/src/guid.rs (100%) rename xpcom/{ => tool}/src/main.rs (100%) rename xpcom/{ => tool}/src/types/mod.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 2cf631a..a9e36f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,5 +11,6 @@ members = [ "u160", "publish-ws", "yagen", - "xpcom" + "xpcom", + "xpcom/tool" ] diff --git a/xpcom/Cargo.toml b/xpcom/Cargo.toml index f51e1ab..62e427b 100644 --- a/xpcom/Cargo.toml +++ b/xpcom/Cargo.toml @@ -6,7 +6,3 @@ 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" diff --git a/xpcom/src/lib.rs b/xpcom/src/lib.rs new file mode 100644 index 0000000..1b4a90c --- /dev/null +++ b/xpcom/src/lib.rs @@ -0,0 +1,8 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + let result = 2 + 2; + assert_eq!(result, 4); + } +} diff --git a/xpcom/tool/Cargo.toml b/xpcom/tool/Cargo.toml new file mode 100644 index 0000000..4af233f --- /dev/null +++ b/xpcom/tool/Cargo.toml @@ -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" diff --git a/xpcom/src/guid.rs b/xpcom/tool/src/guid.rs similarity index 100% rename from xpcom/src/guid.rs rename to xpcom/tool/src/guid.rs diff --git a/xpcom/src/main.rs b/xpcom/tool/src/main.rs similarity index 100% rename from xpcom/src/main.rs rename to xpcom/tool/src/main.rs diff --git a/xpcom/src/types/mod.rs b/xpcom/tool/src/types/mod.rs similarity index 100% rename from xpcom/src/types/mod.rs rename to xpcom/tool/src/types/mod.rs From 25d1fb9a943023ba8218af0546d53b374fe2451d Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Wed, 6 Jul 2022 20:53:09 -0700 Subject: [PATCH 08/15] IUnknown --- xpcom/src/lib.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/xpcom/src/lib.rs b/xpcom/src/lib.rs index 1b4a90c..1d12566 100644 --- a/xpcom/src/lib.rs +++ b/xpcom/src/lib.rs @@ -1,3 +1,41 @@ +use std::sync::atomic::AtomicU32; + +type HRESULT = u32; + +type GUID = u128; + +type ULONG = u32; + +struct IUnknown(&'static IUknownVmt); + +struct IUknownVmt { + QueryInterface: extern "stdcall" fn (this: &mut IUnknown, riid: &GUID, ppvObject: &mut &mut IUnknown) -> HRESULT, + AddRef: extern "stdcall" fn (this: &mut IUnknown) -> ULONG, + Release: extern "stdcall" fn (this: &mut IUnknown) -> ULONG, +} + +#[repr(transparent)] +struct Ref(*mut IUnknown); + +impl Ref { + fn raw(&self) -> &mut IUnknown { unsafe { &mut *self.0 } } + fn new(raw: &mut IUnknown) -> Self { + (raw.0.AddRef)(raw); + Self(raw) + } +} + +impl Drop for Ref { + fn drop(&mut self) { + let raw = self.raw(); + (raw.0.Release)(raw); + } +} + +impl Clone for Ref { + fn clone(&self) -> Self { Self::new(self.raw()) } +} + #[cfg(test)] mod tests { #[test] From c6c6b45508e5024aba0bdb3d5bebb7c61f0266d6 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Wed, 6 Jul 2022 22:15:48 -0700 Subject: [PATCH 09/15] Interface --- xpcom/src/lib.rs | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/xpcom/src/lib.rs b/xpcom/src/lib.rs index 1d12566..33f93c7 100644 --- a/xpcom/src/lib.rs +++ b/xpcom/src/lib.rs @@ -1,46 +1,55 @@ -use std::sync::atomic::AtomicU32; - type HRESULT = u32; type GUID = u128; type ULONG = u32; -struct IUnknown(&'static IUknownVmt); +// + +pub trait Interface: 'static { + const ID: GUID; +} -struct IUknownVmt { - QueryInterface: extern "stdcall" fn (this: &mut IUnknown, riid: &GUID, ppvObject: &mut &mut IUnknown) -> HRESULT, - AddRef: extern "stdcall" fn (this: &mut IUnknown) -> ULONG, - Release: extern "stdcall" fn (this: &mut IUnknown) -> ULONG, +#[repr(transparent)] +pub struct Obj (&'static Vmt); + +#[repr(C)] +struct Vmt { + QueryInterface: extern "stdcall" fn (this: &mut Obj, riid: &GUID, ppvObject: &mut &mut Obj) -> HRESULT, + AddRef: extern "stdcall" fn (this: &mut Obj) -> ULONG, + Release: extern "stdcall" fn (this: &mut Obj) -> ULONG, + interface: I } #[repr(transparent)] -struct Ref(*mut IUnknown); +pub struct Ref(*mut Obj); -impl Ref { - fn raw(&self) -> &mut IUnknown { unsafe { &mut *self.0 } } - fn new(raw: &mut IUnknown) -> Self { +impl Ref { + pub fn raw(&self) -> &mut Obj { unsafe { &mut *self.0 } } + pub fn new(raw: &mut Obj) -> Self { (raw.0.AddRef)(raw); Self(raw) } } -impl Drop for Ref { +impl Drop for Ref { fn drop(&mut self) { let raw = self.raw(); (raw.0.Release)(raw); } } -impl Clone for Ref { +impl Clone for Ref { fn clone(&self) -> Self { Self::new(self.raw()) } } +// + #[cfg(test)] mod tests { + #[test] fn it_works() { - let result = 2 + 2; - assert_eq!(result, 4); + } } From e1418fd3a574eec92a202c3851a61b2441a77c36 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Wed, 6 Jul 2022 23:45:35 -0700 Subject: [PATCH 10/15] Class --- xpcom/src/lib.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/xpcom/src/lib.rs b/xpcom/src/lib.rs index 33f93c7..e669c79 100644 --- a/xpcom/src/lib.rs +++ b/xpcom/src/lib.rs @@ -1,5 +1,7 @@ type HRESULT = u32; +const S_OK: HRESULT = 0; + type GUID = u128; type ULONG = u32; @@ -13,6 +15,7 @@ pub trait Interface: 'static { #[repr(transparent)] pub struct Obj (&'static Vmt); +#[allow(non_snake_case)] #[repr(C)] struct Vmt { QueryInterface: extern "stdcall" fn (this: &mut Obj, riid: &GUID, ppvObject: &mut &mut Obj) -> HRESULT, @@ -45,6 +48,28 @@ impl Clone for Ref { // +pub trait Class { + type Interface: Interface; + const INTERFACE: Self::Interface; +} + +#[allow(non_snake_case)] +trait ClassEx: Class { + const VMT: Vmt = Vmt { + QueryInterface: Self::QueryInterface, + AddRef: Self::AddRef, + Release: Self::Release, + interface: Self::INTERFACE, + }; + extern "stdcall" fn QueryInterface(_this: &mut Obj, _riid: &GUID, _ppvObject: &mut &mut Obj) -> HRESULT { + S_OK + } + extern "stdcall" fn AddRef(_this: &mut Obj) -> ULONG { 0 } + extern "stdcall" fn Release(_this: &mut Obj) -> ULONG { 0 } +} + +impl ClassEx for C {} + #[cfg(test)] mod tests { From 70b7b22c736c8c1271e6636dc62bb850ce92bea6 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Thu, 7 Jul 2022 10:07:41 -0700 Subject: [PATCH 11/15] QueryInterface --- xpcom/src/lib.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/xpcom/src/lib.rs b/xpcom/src/lib.rs index e669c79..0045d9f 100644 --- a/xpcom/src/lib.rs +++ b/xpcom/src/lib.rs @@ -1,6 +1,10 @@ +use std::ptr::{null_mut}; + type HRESULT = u32; const S_OK: HRESULT = 0; +const E_NOINTERFACE: HRESULT = 0x80004002; +const E_POINTER: HRESULT = 0x80004003; type GUID = u128; @@ -18,7 +22,7 @@ pub struct Obj (&'static Vmt); #[allow(non_snake_case)] #[repr(C)] struct Vmt { - QueryInterface: extern "stdcall" fn (this: &mut Obj, riid: &GUID, ppvObject: &mut &mut Obj) -> HRESULT, + QueryInterface: extern "stdcall" fn (this: &mut Obj, riid: &GUID, ppvObject: *mut *mut Obj) -> HRESULT, AddRef: extern "stdcall" fn (this: &mut Obj) -> ULONG, Release: extern "stdcall" fn (this: &mut Obj) -> ULONG, interface: I @@ -61,8 +65,16 @@ trait ClassEx: Class { Release: Self::Release, interface: Self::INTERFACE, }; - extern "stdcall" fn QueryInterface(_this: &mut Obj, _riid: &GUID, _ppvObject: &mut &mut Obj) -> HRESULT { - S_OK + extern "stdcall" fn QueryInterface(this: &mut Obj, riid: &GUID, ppvObject: *mut *mut Obj) -> HRESULT { + if ppvObject == null_mut() { + E_POINTER + } else if Self::Interface::ID == *riid { + unsafe { *ppvObject = &mut *this }; + S_OK + } else { + unsafe { *ppvObject = null_mut() }; + E_NOINTERFACE + } } extern "stdcall" fn AddRef(_this: &mut Obj) -> ULONG { 0 } extern "stdcall" fn Release(_this: &mut Obj) -> ULONG { 0 } From 5b83b4170e6967580586a636f7d2675e4a0a0ebf Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Thu, 7 Jul 2022 10:27:08 -0700 Subject: [PATCH 12/15] QueryInterface with AddRef --- xpcom/src/lib.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/xpcom/src/lib.rs b/xpcom/src/lib.rs index 0045d9f..2cee40a 100644 --- a/xpcom/src/lib.rs +++ b/xpcom/src/lib.rs @@ -67,14 +67,16 @@ trait ClassEx: Class { }; extern "stdcall" fn QueryInterface(this: &mut Obj, riid: &GUID, ppvObject: *mut *mut Obj) -> HRESULT { if ppvObject == null_mut() { - E_POINTER - } else if Self::Interface::ID == *riid { - unsafe { *ppvObject = &mut *this }; - S_OK - } else { - unsafe { *ppvObject = null_mut() }; - E_NOINTERFACE + return E_POINTER } + let result: (*mut Obj, HRESULT) = if Self::Interface::ID == *riid { + Self::AddRef(this); + (this, S_OK) + } else { + (null_mut(), E_NOINTERFACE) + }; + unsafe { *ppvObject = result.0 } + result.1 } extern "stdcall" fn AddRef(_this: &mut Obj) -> ULONG { 0 } extern "stdcall" fn Release(_this: &mut Obj) -> ULONG { 0 } From 4f5c21db62dfa74d8bfd3b57bbdbabc0025eab84 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Thu, 7 Jul 2022 13:05:29 -0700 Subject: [PATCH 13/15] counter --- xpcom/src/lib.rs | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/xpcom/src/lib.rs b/xpcom/src/lib.rs index 2cee40a..9d24aa6 100644 --- a/xpcom/src/lib.rs +++ b/xpcom/src/lib.rs @@ -1,4 +1,4 @@ -use std::ptr::{null_mut}; +use std::{ptr::{null_mut}, sync::atomic::{AtomicU32, Ordering}}; type HRESULT = u32; @@ -17,14 +17,14 @@ pub trait Interface: 'static { } #[repr(transparent)] -pub struct Obj (&'static Vmt); +pub struct Obj (&'static Vmt, I>); #[allow(non_snake_case)] #[repr(C)] -struct Vmt { - QueryInterface: extern "stdcall" fn (this: &mut Obj, riid: &GUID, ppvObject: *mut *mut Obj) -> HRESULT, - AddRef: extern "stdcall" fn (this: &mut Obj) -> ULONG, - Release: extern "stdcall" fn (this: &mut Obj) -> ULONG, +struct Vmt { + 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 } @@ -52,24 +52,31 @@ impl Clone for Ref { // -pub trait Class { +pub trait Class: 'static + Sized { type Interface: Interface; const INTERFACE: Self::Interface; } +#[repr(C)] +struct ClassObj { + vmt: &'static Vmt, + counter: AtomicU32, + value: C, +} + #[allow(non_snake_case)] trait ClassEx: Class { - const VMT: Vmt = Vmt { + const VMT: Vmt, Self::Interface> = Vmt { QueryInterface: Self::QueryInterface, AddRef: Self::AddRef, Release: Self::Release, interface: Self::INTERFACE, }; - extern "stdcall" fn QueryInterface(this: &mut Obj, riid: &GUID, ppvObject: *mut *mut Obj) -> HRESULT { + extern "stdcall" fn QueryInterface(this: &mut ClassObj, riid: &GUID, ppvObject: *mut *mut ClassObj) -> HRESULT { if ppvObject == null_mut() { return E_POINTER } - let result: (*mut Obj, HRESULT) = if Self::Interface::ID == *riid { + let result: (*mut ClassObj, HRESULT) = if Self::Interface::ID == *riid { Self::AddRef(this); (this, S_OK) } else { @@ -78,8 +85,19 @@ trait ClassEx: Class { unsafe { *ppvObject = result.0 } result.1 } - extern "stdcall" fn AddRef(_this: &mut Obj) -> ULONG { 0 } - extern "stdcall" fn Release(_this: &mut Obj) -> ULONG { 0 } + extern "stdcall" fn AddRef(this: &mut ClassObj) -> ULONG { + this.counter.fetch_add(1, Ordering::Relaxed) + 1 + } + extern "stdcall" fn Release(this: &mut ClassObj) -> ULONG { + match this.counter.fetch_sub(1, Ordering::Relaxed) { + 0 => panic!("release"), + 1 => { + unsafe { Box::from_raw(this) }; + 0 + } + c => c - 1 + } + } } impl ClassEx for C {} From 7fb5b05e7834d431d86d8863adc44e68da1d17c0 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Thu, 7 Jul 2022 14:40:23 -0700 Subject: [PATCH 14/15] ClassObject --- xpcom/src/lib.rs | 84 ++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/xpcom/src/lib.rs b/xpcom/src/lib.rs index 9d24aa6..3b68f89 100644 --- a/xpcom/src/lib.rs +++ b/xpcom/src/lib.rs @@ -1,4 +1,7 @@ -use std::{ptr::{null_mut}, sync::atomic::{AtomicU32, Ordering}}; +use std::{ + ptr::null_mut, + sync::atomic::{AtomicU32, Ordering}, +}; type HRESULT = u32; @@ -17,22 +20,25 @@ pub trait Interface: 'static { } #[repr(transparent)] -pub struct Obj (&'static Vmt, I>); +pub struct Obj(&'static Vmt, I>); #[allow(non_snake_case)] #[repr(C)] struct Vmt { - 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 + 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(*mut Obj); impl Ref { - pub fn raw(&self) -> &mut Obj { unsafe { &mut *self.0 } } + pub fn raw(&self) -> &mut Obj { + unsafe { &mut *self.0 } + } pub fn new(raw: &mut Obj) -> Self { (raw.0.AddRef)(raw); Self(raw) @@ -47,7 +53,9 @@ impl Drop for Ref { } impl Clone for Ref { - fn clone(&self) -> Self { Self::new(self.raw()) } + fn clone(&self) -> Self { + Self::new(self.raw()) + } } // @@ -59,54 +67,62 @@ pub trait Class: 'static + Sized { #[repr(C)] struct ClassObj { - vmt: &'static Vmt, + vmt: Box>, counter: AtomicU32, value: C, } -#[allow(non_snake_case)] -trait ClassEx: Class { - const VMT: Vmt, Self::Interface> = Vmt { - QueryInterface: Self::QueryInterface, - AddRef: Self::AddRef, - Release: Self::Release, - interface: Self::INTERFACE, - }; - extern "stdcall" fn QueryInterface(this: &mut ClassObj, riid: &GUID, ppvObject: *mut *mut ClassObj) -> HRESULT { +impl ClassObj { + extern "stdcall" fn QueryInterface( + &mut self, + riid: &GUID, + ppvObject: *mut *mut Self, + ) -> HRESULT { if ppvObject == null_mut() { - return E_POINTER + return E_POINTER; } - let result: (*mut ClassObj, HRESULT) = if Self::Interface::ID == *riid { - Self::AddRef(this); - (this, S_OK) + 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(this: &mut ClassObj) -> ULONG { - this.counter.fetch_add(1, Ordering::Relaxed) + 1 + extern "stdcall" fn AddRef(&mut self) -> ULONG { + self.counter.fetch_add(1, Ordering::Relaxed) + 1 } - extern "stdcall" fn Release(this: &mut ClassObj) -> ULONG { - match this.counter.fetch_sub(1, Ordering::Relaxed) { + extern "stdcall" fn Release(&mut self) -> ULONG { + match self.counter.fetch_sub(1, Ordering::Relaxed) { 0 => panic!("release"), - 1 => { - unsafe { Box::from_raw(this) }; + 1 => { + unsafe { Box::from_raw(self) }; 0 } - c => c - 1 + c => c - 1, } } -} +} -impl ClassEx for C {} +pub fn new(value: C) -> Ref { + let p = Box::new(ClassObj { + vmt: Box::new(Vmt { + QueryInterface: ClassObj::QueryInterface, + AddRef: ClassObj::AddRef, + Release: ClassObj::Release, + interface: C::INTERFACE, + }), + counter: AtomicU32::default(), + value, + }); + let i = Box::into_raw(p) as *mut Obj; + Ref::new(unsafe { &mut *i }) +} #[cfg(test)] mod tests { #[test] - fn it_works() { - - } + fn it_works() {} } From ba583c7a3f146f8aad38c57026919ebaace47f33 Mon Sep 17 00:00:00 2001 From: Sergey Shandar Date: Thu, 7 Jul 2022 14:45:02 -0700 Subject: [PATCH 15/15] ClassObj::new --- xpcom/src/lib.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/xpcom/src/lib.rs b/xpcom/src/lib.rs index 3b68f89..e1626ef 100644 --- a/xpcom/src/lib.rs +++ b/xpcom/src/lib.rs @@ -73,6 +73,18 @@ struct ClassObj { } impl ClassObj { + fn new(value: C) -> Box { + 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, @@ -106,17 +118,7 @@ impl ClassObj { } pub fn new(value: C) -> Ref { - let p = Box::new(ClassObj { - vmt: Box::new(Vmt { - QueryInterface: ClassObj::QueryInterface, - AddRef: ClassObj::AddRef, - Release: ClassObj::Release, - interface: C::INTERFACE, - }), - counter: AtomicU32::default(), - value, - }); - let i = Box::into_raw(p) as *mut Obj; + let i = Box::into_raw(ClassObj::new(value)) as *mut Obj; Ref::new(unsafe { &mut *i }) }