[vlc-commits] [Git][videolan/vlc][master] 3 commits: vlcrs-macros: import ModuleProtocol trait

Steve Lhomme (@robUx4) gitlab at videolan.org
Tue Jul 16 12:15:51 UTC 2024



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
d8a22120 by Alexandre Janniaux at 2024-07-16T11:38:06+00:00
vlcrs-macros: import ModuleProtocol trait

The trait is usable only if it is imported into the generated code from
the macro, so import it from vlcrs-plugin to avoid having the user
import it themselves.

- - - - -
a6ffd5c5 by Alexandre Janniaux at 2024-07-16T11:38:06+00:00
vlcrs-macros: fix capability naming

We don't need it to be an identifier now.

- - - - -
f9f02219 by Alexandre Janniaux at 2024-07-16T11:38:06+00:00
vlcrs-macros: change how capability trait works

The previous design for the capability trait was working like this:

1/ User was defining a manifest including

    module!{
        type: ModuleImplType (CapabilityTrait),
        ...
    }

where CapabilityTrait was the general trait being implemented and
exposing the module interface, and ModuleImplType the type representing
the module implementation from the implementor.

2/ Core was defining the CapabilityTrait with a loader

    trait CapabilityTrait {
        type Loader = ...;
        type Activate = ...;
        type Deactivate = ...;

        /* Rest of the required implementation for modules */
    }

where Activate and Deactivate are the types for the module callbacks and
Loader is a type providing those functions to setup the callbacks.

It was working well to define the manifest and setup the capability,
since we could have monomorphized activation functions using the real
type of the module implementation by typing the loader with Self.

    unsafe extern "C"
    fn activate_filter<T: CapabilityTrait>(
        obj: *mut vlc_filter_t,
        valid: &mut boo
    ) -> c_int {
        T::open(obj, valid);
        0
    }

However, it made the virtual tables for operations impossible to write
since they could not be monomorphized. Indeed, it is not possible to
write the following because only one static/const variable exists for
every generic types given:

    fn activate<T: EncoderCapability>(obj: *mut encoder_t) {
        static ENCODER_OPS : vlc_encoder_operations = vlc_encoder_operations{
            encode_video: encode_video_impl::<T>
        };
        (*obj).sys = &ENCODER_OPS;
    }

Instead, dynamic dispatch needs to be used to forward from the trait
implementation directly, but it would mean writing:

    fn encode_video_impl(encoder: *mut encoder_t) {
        let implementation = (*encoder).sys
            as *mut Box<dyn EncoderCapability<
                Loader=EncoderCapabilityLoader,
                Activate=vlc_activate_encoder,
                Deactivate=vlc_deactivate_encoder>>;
        (*implementation).encode_video(...);
    }

Which completely defeat the purpose of the associated default setup for
the capability trait.

By summarizing the situation, we can find the following graph:

            VLC module loading  ____
                                    \
                                     v
    +------------+     (3)      +------------+
    | Capability |<-------------|  Activate  |
    | trait      |              |  Functions |
    +------------+              +------------+
          ^       \                    |
          |        \   (2)             |
          | (1)     ---------.         | (4)
          |                   \        |
          |                    \       v
    +------------+              +------------+
    |   Loader   |     (5)      |   Module   |
    |   Vtable   |------------->|   Impl     |
    +------------+              +------------+
           ^
            \___ VLC module API

    (1): p_sys, we don't know the real type
    (2): implements the trait
    (3): <T: CapabilityTrait>, uses the real type
    (4): <T: CapabilityTrait>, uses the real type
    (5): dyn CapabilityTrait, dynamic dispatch

This commit changes the definition of new capabilities and the plugin
manifest entry, asking the user to provide the module loader instead of
the capability trait.

    module!{
        type: ModuleImplType (CapabilityTraitLoader),
        ...
    }

It allows removing Activate, Deactivate and Loader from the interface
exposed by the capability trait, removing uneeded details for the end
users, and allowing to require the ModuleProtocol<T> trait on those
loaders, as well as getting a real type and not a trait in the module
macros. It also removes the dependency to associated_type_defaults
for code creating new capability as only vlcrs-plugin/vlcrs-core will
depend on this feature.

This protocol has the defined associated types Activate and Deactivate
moved towards the implementation of the trait rather than on the trait
itself. In the end, users can now use dyn CapabilityTrait without
specifying Loader, Activate and Deactivate types, effectively separating
the VLC core interface from the exposed Rust API.

The implementation has been tested against the re-implementation of
rav1e encoder in Rust, to check whether it was possible to write the
virtual tables and activation functions correctly. Unfortunately, the
lack of the correct type in the virtual tables means that we can only
use the trait object, which require an additional level of boxing or
additional complexity to have thiner trait objects, but that's not
visible to the final plugin and can be changed later.

- - - - -


7 changed files:

- src/rust/vlcrs-macros/src/lib.rs
- src/rust/vlcrs-macros/src/module.rs
- src/rust/vlcrs-macros/tests/module.rs
- src/rust/vlcrs-macros/tests/module_default.rs
- src/rust/vlcrs-macros/tests/module_multiple.rs
- src/rust/vlcrs-macros/tests/module_specific.rs
- src/rust/vlcrs-plugin/src/lib.rs


Changes:

=====================================
src/rust/vlcrs-macros/src/lib.rs
=====================================
@@ -13,27 +13,19 @@ mod module;
 /// # use std::ffi::{c_int, c_void};
 /// # type ActivateFunction = unsafe extern "C" fn() -> c_int;
 /// # type DeactivateFunction = unsafe extern "C" fn() -> c_void;
-/// # pub trait CapabilityTrait {
+/// # pub trait CapabilityTrait {}
+/// # extern "C" fn activate() -> c_int{ 0 }
+/// # pub struct CapabilityTraitLoader;
+/// # impl<T: CapabilityTrait> ModuleProtocol<T> for CapabilityTraitLoader {
 /// #     type Activate = ActivateFunction;
 /// #     type Deactivate = DeactivateFunction;
-/// #     type Loader = CapabilityTraitLoader<Self>;
-/// # }
-/// # extern "C" fn activate() -> c_int{ 0 }
-/// # pub struct CapabilityTraitLoader<T: ?Sized> {
-/// #     _phantom : std::marker::PhantomData<T>
-/// # }
-/// # impl<T: ?Sized + CapabilityTrait> ModuleProtocol<
-/// #     T,
-/// #     ActivateFunction,
-/// #     DeactivateFunction>
-/// # for CapabilityTraitLoader<T> {
 /// #     fn activate_function() -> ActivateFunction { activate }
 /// #     fn deactivate_function() -> Option<DeactivateFunction> { None }
 /// # }
 /// struct MyModule {}
 /// impl CapabilityTrait for MyModule {}
 /// module! {
-///     type: MyModule (CapabilityTrait),
+///     type: MyModule (CapabilityTraitLoader),
 ///     shortname: "infrs",
 ///     shortcuts: ["mp4", "MP4A"],
 ///     description: "This a Rust Module - inflate-rs",
@@ -75,27 +67,20 @@ mod module;
 /// # use std::ffi::{c_int, c_void};
 /// # type ActivateFunction = unsafe extern "C" fn() -> c_int;
 /// # type DeactivateFunction = unsafe extern "C" fn() -> c_void;
-/// # pub trait CapabilityTrait {
+/// # pub trait CapabilityTrait {}
+/// # extern "C" fn activate() -> c_int{ 0 }
+/// # pub struct CapabilityTraitLoader;
+/// # impl<T: CapabilityTrait> ModuleProtocol<T>
+/// # for CapabilityTraitLoader {
 /// #     type Activate = ActivateFunction;
 /// #     type Deactivate = DeactivateFunction;
-/// #     type Loader = CapabilityTraitLoader<Self>;
-/// # }
-/// # extern "C" fn activate() -> c_int{ 0 }
-/// # pub struct CapabilityTraitLoader<T: ?Sized> {
-/// #     _phantom : std::marker::PhantomData<T>
-/// # }
-/// # impl<T: ?Sized + CapabilityTrait> ModuleProtocol<
-/// #     T,
-/// #     ActivateFunction,
-/// #     DeactivateFunction>
-/// # for CapabilityTraitLoader<T> {
 /// #     fn activate_function() -> ActivateFunction { activate }
 /// #     fn deactivate_function() -> Option<DeactivateFunction> { None }
 /// # }
 /// struct Inflate {}
 /// impl CapabilityTrait for Inflate {}
 /// module! {
-///     type: Inflate (CapabilityTrait),
+///     type: Inflate (CapabilityTraitLoader),
 ///     shortcuts: ["mp4", "MP4A"],
 ///     shortname: "infrs",
 ///     description: "This a Rust Module - inflate-rs",


=====================================
src/rust/vlcrs-macros/src/module.rs
=====================================
@@ -45,7 +45,7 @@ struct SubmoduleInfo {
 
 struct ModuleInfo {
     type_: Ident,
-    trait_: Ident,
+    loader: Ident,
     category: Ident,
     capability: CapabilityInfo,
     description: LitStr,
@@ -60,7 +60,7 @@ struct ModuleInfo {
 impl Parse for ModuleInfo {
     fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
         let mut type_ = None;
-        let mut trait_ = None;
+        let mut loader = None;
         let mut category = None;
         let mut capability = None;
         let mut description = None;
@@ -89,7 +89,7 @@ impl Parse for ModuleInfo {
                 type_ = Some(input.parse()?);
                 let parenthesis_content;
                 parenthesized!(parenthesis_content in input);
-                trait_ = Some(parenthesis_content.parse()?);
+                loader = Some(parenthesis_content.parse()?);
                 input.parse::<Token![,]>()?;
                 continue;
             }
@@ -200,8 +200,8 @@ impl Parse for ModuleInfo {
             return Err(input.error("missing `type` key"));
         };
 
-        let Some(trait_) = trait_ else {
-            return Err(input.error("invalid `type` key, missing module trait"));
+        let Some(loader) = loader else {
+            return Err(input.error("invalid `type` key, missing module loader"));
         };
 
         let Some(capability) = capability else {
@@ -222,7 +222,7 @@ impl Parse for ModuleInfo {
 
         Ok(ModuleInfo {
             type_,
-            trait_,
+            loader,
             category,
             capability,
             description,
@@ -514,7 +514,7 @@ fn vlc_param_name(module_info: &ModuleInfo, param: &ParameterInfo) -> String {
 fn generate_module_code(module_info: &ModuleInfo) -> TokenStream2 {
     let ModuleInfo {
         type_,
-        trait_,
+        loader,
         category,
         description,
         help,
@@ -533,7 +533,7 @@ fn generate_module_code(module_info: &ModuleInfo) -> TokenStream2 {
     let description_with_nul = tt_c_str!(description.span() => description.value());
     let name_with_nul = tt_c_str!(type_.span() => name);
 
-    let module = Ident::new(&capability.value(), capability.span());
+    let module = &capability.value();
     let capability_with_nul = tt_c_str!(capability.span() =>
                                         capability.value());
 
@@ -940,9 +940,9 @@ fn generate_module_code(module_info: &ModuleInfo) -> TokenStream2 {
                     #module_open_with_nul,
                     unsafe {
                         std::mem::transmute::<
-                            <#type_ as #trait_>::Activate,
+                            <#loader as ModuleProtocol<#type_>>::Activate,
                             *mut std::ffi::c_void
-                        >(<#type_ as #trait_>::Loader::activate_function())
+                        >(<#loader as ModuleProtocol<#type_>>::activate_function())
                     }
                 )
             } != 0
@@ -950,7 +950,7 @@ fn generate_module_code(module_info: &ModuleInfo) -> TokenStream2 {
                 return -1;
             }
 
-            if <#type_ as #trait_>::Loader::deactivate_function() != None {
+            if <#loader as ModuleProtocol<#type_>>::deactivate_function() != None {
                 if unsafe {
                     vlc_set(
                         opaque,
@@ -959,9 +959,9 @@ fn generate_module_code(module_info: &ModuleInfo) -> TokenStream2 {
                         #module_close_with_nul,
                         unsafe {
                             std::mem::transmute::<
-                                <#type_ as #trait_>::Deactivate,
+                                <#loader as ModuleProtocol<#type_>>::Deactivate,
                                 *mut std::ffi::c_void
-                            >(<#type_ as #trait_>::Loader::deactivate_function().unwrap())
+                            >(<#loader as ModuleProtocol<#type_>>::deactivate_function().unwrap())
                         }
                     )
                 } != 0
@@ -1076,6 +1076,7 @@ pub fn module(input: TokenStream) -> TokenStream {
             vlc_set: ::vlcrs_plugin::sys::vlc_set_cb,
             opaque: *mut ::std::ffi::c_void,
         ) -> i32 {
+            use vlcrs_plugin::ModuleProtocol;
             let mut module: *mut ::vlcrs_plugin::module_t = ::std::ptr::null_mut();
             let mut config: *mut ::vlcrs_plugin::vlc_param = ::std::ptr::null_mut();
 


=====================================
src/rust/vlcrs-macros/tests/module.rs
=====================================
@@ -3,7 +3,6 @@
 //
 
 #![feature(c_variadic)]
-#![feature(associated_type_defaults)]
 #![feature(extern_types)]
 #![feature(fn_ptr_trait)]
 
@@ -13,7 +12,6 @@ use common::TestContext;
 use vlcrs_macros::module;
 
 use std::ffi::c_int;
-use std::marker::PhantomData;
 
 use vlcrs_plugin::{vlc_activate, vlc_deactivate};
 
@@ -29,28 +27,26 @@ fn deactivate_test<T: SpecificCapabilityModule>(_obj: *mut vlcrs_plugin::vlc_obj
 
 use vlcrs_plugin::ModuleProtocol;
 
-pub struct ModuleLoader<T> { _phantom: PhantomData<T> }
-impl<T> ModuleProtocol<T, vlc_activate, vlc_deactivate> for ModuleLoader<T>
+pub struct ModuleLoader;
+impl<T> ModuleProtocol<T> for ModuleLoader
     where T: SpecificCapabilityModule
 {
-    fn activate_function() -> vlc_activate
+    type Activate = vlc_activate;
+    type Deactivate = vlc_deactivate;
+
+    fn activate_function() -> Self::Activate
     {
         activate_test::<T>
     }
 
-    fn deactivate_function() -> Option<vlc_deactivate>
+    fn deactivate_function() -> Option<Self::Deactivate>
     {
         Some(deactivate_test::<T>)
     }
 }
 
 /* Implement dummy module */
-pub trait SpecificCapabilityModule : Sized {
-    type Activate = vlc_activate;
-    type Deactivate = vlc_deactivate;
-
-    type Loader = ModuleLoader<Self>;
-
+pub trait SpecificCapabilityModule {
     fn open();
 }
 pub struct TestModule;
@@ -61,7 +57,7 @@ impl SpecificCapabilityModule for TestModule {
 }
 
 module! {
-    type: TestModule (SpecificCapabilityModule),
+    type: TestModule (ModuleLoader),
     capability: "video_filter" @ 0,
     category: VIDEO_VFILTER,
     description: "A new module",


=====================================
src/rust/vlcrs-macros/tests/module_default.rs
=====================================
@@ -13,7 +13,6 @@ use common::TestContext;
 use vlcrs_macros::module;
 
 use std::ffi::c_int;
-use std::marker::PhantomData;
 use vlcrs_plugin::{ModuleProtocol,vlc_activate};
 
 unsafe extern "C"
@@ -26,16 +25,16 @@ fn activate_filter(_obj: *mut vlcrs_plugin::vlc_object_t) -> c_int
 //
 // Create an implementation loader for the TestFilterCapability
 //
-pub struct FilterModuleLoader<T> {
-    _phantom: PhantomData<T>
-}
+pub struct FilterModuleLoader;
 
 ///
 /// Signal the core that we can load modules with this loader
 ///
-impl<T> ModuleProtocol<T, vlc_activate> for FilterModuleLoader<T>
+impl<T> ModuleProtocol<T> for FilterModuleLoader
     where T: TestNoDeactivateCapability
 {
+    type Activate = vlc_activate;
+    type Deactivate = *mut ();
     fn activate_function() -> vlc_activate
     {
         activate_filter
@@ -43,12 +42,7 @@ impl<T> ModuleProtocol<T, vlc_activate> for FilterModuleLoader<T>
 }
 
 /* Implement dummy module capability */
-pub trait TestNoDeactivateCapability : Sized {
-    type Activate = vlc_activate;
-    type Deactivate = *mut ();
-
-    type Loader = FilterModuleLoader<Self>;
-}
+pub trait TestNoDeactivateCapability {}
 
 ///
 /// Create a dummy module using this capability
@@ -61,7 +55,7 @@ impl TestNoDeactivateCapability for TestModule {}
 // and this module.
 //
 module! {
-    type: TestModule (TestNoDeactivateCapability),
+    type: TestModule (FilterModuleLoader),
     capability: "video_filter" @ 0,
     category: VIDEO_VFILTER,
     description: "A new module",


=====================================
src/rust/vlcrs-macros/tests/module_multiple.rs
=====================================
@@ -3,7 +3,6 @@
 //
 
 #![feature(c_variadic)]
-#![feature(associated_type_defaults)]
 #![feature(extern_types)]
 #![feature(fn_ptr_trait)]
 
@@ -13,7 +12,6 @@ use common::TestContext;
 use vlcrs_macros::module;
 
 use std::ffi::c_int;
-use std::marker::PhantomData;
 use vlcrs_plugin::ModuleProtocol;
 
 extern {
@@ -32,32 +30,33 @@ fn activate_filter<T: TestFilterCapability>(_obj: *mut vlc_filter_t, valid: &mut
     0
 }
 
+unsafe extern "C"
+fn activate_other_filter<T: TestOtherCapability>(_obj: *mut vlc_filter_t, valid: &mut bool) -> c_int
+{
+    T::open(_obj, valid);
+    0
+}
+
 //
 // Create an implementation loader for the TestFilterCapability
 //
-pub struct FilterModuleLoader<T> {
-    _phantom: PhantomData<T>
-}
+pub struct FilterModuleLoader;
 
 ///
 /// Signal the core that we can load modules with this loader
 ///
-impl<T> ModuleProtocol<T, vlc_filter_activate> for FilterModuleLoader<T>
+impl<T> ModuleProtocol<T> for FilterModuleLoader
     where T: TestFilterCapability
 {
-    fn activate_function() -> vlc_filter_activate
+    type Activate = vlc_filter_activate;
+    fn activate_function() -> Self::Activate
     {
         activate_filter::<T>
     }
 }
 
 /* Implement dummy module capability */
-pub trait TestFilterCapability : Sized {
-    type Activate = vlc_filter_activate;
-    type Deactivate = *mut ();
-
-    type Loader = FilterModuleLoader<Self>;
-
+pub trait TestFilterCapability {
     fn open(obj: *mut vlc_filter_t, bool: &mut bool);
 }
 
@@ -72,14 +71,20 @@ impl TestFilterCapability for TestModuleFilter {
 }
 
 /* Implement dummy module capability */
-pub trait TestOtherCapability : Sized {
-    type Activate = vlc_filter_activate;
-    type Deactivate = *mut ();
-    type Loader = FilterModuleLoader<Self>;
-
+pub trait TestOtherCapability  {
     fn open(obj: *mut vlc_filter_t, bool: &mut bool);
 }
 
+struct TestOtherCapabilityLoader;
+impl<T> ModuleProtocol<T> for TestOtherCapabilityLoader
+    where T: TestOtherCapability
+{
+    type Activate = vlc_filter_activate;
+    fn activate_function() -> Self::Activate {
+        activate_other_filter::<T>
+    }
+}
+
 ///
 /// Create a dummy module using this capability
 ///
@@ -95,7 +100,7 @@ impl TestOtherCapability for TestModuleFilter {
 // and this module.
 //
 module! {
-    type: TestModuleFilter (TestFilterCapability),
+    type: TestModuleFilter (FilterModuleLoader),
     capability: "video_filter" @ 0,
     category: VIDEO_VFILTER,
     description: "A new module",
@@ -103,7 +108,7 @@ module! {
     shortcuts: ["mynewmodule_filter"],
     submodules: [
         {
-            type: TestModuleFilter (TestOtherCapability),
+            type: TestModuleFilter (TestOtherCapabilityLoader),
             capability: "other_capability" @ 0,
             category: VIDEO_VFILTER,
             description: "Another module",


=====================================
src/rust/vlcrs-macros/tests/module_specific.rs
=====================================
@@ -3,7 +3,6 @@
 //
 
 #![feature(c_variadic)]
-#![feature(associated_type_defaults)]
 #![feature(extern_types)]
 #![feature(fn_ptr_trait)]
 
@@ -13,7 +12,6 @@ use common::TestContext;
 use vlcrs_macros::module;
 
 use std::ffi::c_int;
-use std::marker::PhantomData;
 use vlcrs_plugin::ModuleProtocol;
 
 extern {
@@ -45,33 +43,29 @@ fn deactivate_filter<T: TestFilterCapability>(_obj: *mut vlc_filter_t, valid: &m
 //
 // Create an implementation loader for the TestFilterCapability
 //
-pub struct FilterModuleLoader<T> {
-    _phantom: PhantomData<T>
-}
+pub struct FilterModuleLoader;
 
 ///
 /// Signal the core that we can load modules with this loader
 ///
-impl<T> ModuleProtocol<T, vlc_filter_activate, vlc_filter_deactivate> for FilterModuleLoader<T>
+impl<T> ModuleProtocol<T> for FilterModuleLoader
     where T: TestFilterCapability
 {
-    fn activate_function() -> vlc_filter_activate
+    type Activate = vlc_filter_activate;
+    type Deactivate = vlc_filter_deactivate;
+
+    fn activate_function() -> Self::Activate
     {
         activate_filter::<T>
     }
 
-    fn deactivate_function() -> Option<vlc_filter_deactivate> {
+    fn deactivate_function() -> Option<Self::Deactivate> {
         Some(deactivate_filter::<T>)
     }
 }
 
 /* Implement dummy module capability */
-pub trait TestFilterCapability : Sized {
-    type Activate = vlc_filter_activate;
-    type Deactivate = vlc_filter_deactivate;
-
-    type Loader = FilterModuleLoader<Self>;
-
+pub trait TestFilterCapability {
     fn open(obj: *mut vlc_filter_t, bool: &mut bool);
     fn close(obj: *mut vlc_filter_t, valid: &mut bool);
 }
@@ -95,7 +89,7 @@ impl TestFilterCapability for TestModuleFilter {
 // and this module.
 //
 module! {
-    type: TestModuleFilter (TestFilterCapability),
+    type: TestModuleFilter (FilterModuleLoader),
     capability: "video_filter" @ 0,
     category: VIDEO_VFILTER,
     description: "A new module",


=====================================
src/rust/vlcrs-plugin/src/lib.rs
=====================================
@@ -1,4 +1,5 @@
 #![feature(extern_types)]
+#![feature(associated_type_defaults)]
 
 pub mod sys;
 
@@ -211,8 +212,6 @@ pub type vlc_deactivate = unsafe extern "C" fn(*mut vlc_object_t);
 /// * `Deactivate`: Type for the deactivation function
 ///
 /// ```no_run
-/// #![feature(associated_type_defaults)]
-/// use std::marker::PhantomData;
 /// use vlcrs_plugin::ModuleProtocol;
 ///
 /// /* New trait bringing support for new capabilities in modules. */
@@ -221,9 +220,6 @@ pub type vlc_deactivate = unsafe extern "C" fn(*mut vlc_object_t);
 /// type DeactivateFunction = unsafe extern "C" fn();
 /// trait NewCapabilityTrait {
 ///     /* Mandatory type definition for capability traits */
-///     type Activate = ActivateFunction;
-///     type Deactivate = DeactivateFunction;
-///     type Loader = NewCapabilityLoader<Self>;
 ///
 ///     /* Example capability interface, can be anything and can add
 ///      * as many function as required. */
@@ -231,25 +227,27 @@ pub type vlc_deactivate = unsafe extern "C" fn(*mut vlc_object_t);
 /// }
 ///
 /// /* Implement a function to load modules implementing NewCapabilityTrait. */
-/// unsafe extern "C" fn activate_new_capability<ModuleType: ?Sized + NewCapabilityTrait>() {
+/// unsafe extern "C" fn activate_new_capability<ModuleType: NewCapabilityTrait>() {
 ///     /* Do anything needed to initialize the module, for instance initializing
 ///      * a ModuleType object and call the open() function on it. */
 /// }
 ///
 /// /* Implement a module loader for this new capability trait. */
-/// struct NewCapabilityLoader<ModuleType: ?Sized> { _phantom : PhantomData<ModuleType> }
-/// impl<ModuleType> ModuleProtocol<
-///     ModuleType,
-///     ActivateFunction,
-///     DeactivateFunction>
-/// for NewCapabilityLoader<ModuleType>
-/// where ModuleType : ?Sized + NewCapabilityTrait {
+/// struct NewCapabilityLoader;
+/// impl<ModuleType> ModuleProtocol<ModuleType>
+/// for NewCapabilityLoader
+/// where ModuleType : NewCapabilityTrait {
+///     type Activate = ActivateFunction;
+///     type Deactivate = DeactivateFunction;
+///
 ///     fn activate_function() -> ActivateFunction { activate_new_capability::<ModuleType> }
 ///     fn deactivate_function() -> Option<DeactivateFunction> { None }
 /// }
 /// ```
-pub trait ModuleProtocol<ModuleType: ?Sized, Activate, Deactivate=*mut ()>
+pub trait ModuleProtocol<ModuleType: ?Sized>
 {
-    fn activate_function() -> Activate;
-    fn deactivate_function() -> Option<Deactivate> { None }
+    type Activate;
+    type Deactivate = *mut ();
+    fn activate_function() -> Self::Activate;
+    fn deactivate_function() -> Option<Self::Deactivate> { None }
 }



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/838393e66c7c03987f8927766b99359f12ef8a75...f9f022198b4dfeb48302fbadffdc309ac0d40004

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/838393e66c7c03987f8927766b99359f12ef8a75...f9f022198b4dfeb48302fbadffdc309ac0d40004
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list