1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#![macro_use]

#[macro_export]
macro_rules! ipc_sf_define_interface_trait {
    (
        trait $intf:ident {
            $(
                $name:ident [$rq_id:expr, $ver_intv:expr]: ( $( $in_param_name:ident: $in_param_type:ty ),* ) => ( $( $out_param_name:ident: $out_param_type:ty ),* )
            );* $(;)* // Note: trick to allow last trailing ';' for proper styling
        }
    ) => {
        paste::paste! {
            pub trait $intf: $crate::ipc::sf::IObject {
                $(
                    #[allow(unused_parens)]
                    fn $name(&mut self, $( $in_param_name: $in_param_type ),* ) -> $crate::result::Result<( $( $out_param_type ),* )>;
        
                    #[allow(unused_assignments)]
                    #[allow(unused_parens)]
                    fn [<sf_server_impl_ $name>](&mut self, protocol: $crate::ipc::CommandProtocol, mut ctx: &mut $crate::ipc::server::ServerContext) -> $crate::result::Result<()> {
                        ctx.raw_data_walker = $crate::ipc::DataWalker::new(ctx.ctx.in_params.data_offset);
                        $( let $in_param_name = <$in_param_type as $crate::ipc::server::RequestCommandParameter<_>>::after_request_read(&mut ctx)?; )*
        
                        let ( $( $out_param_name ),* ) = self.$name( $( $in_param_name ),* )?;
        
                        ctx.raw_data_walker = $crate::ipc::DataWalker::new(core::ptr::null_mut());
                        $( $crate::ipc::server::ResponseCommandParameter::before_response_write(&$out_param_name, &mut ctx)?; )*
                        ctx.ctx.out_params.data_size = ctx.raw_data_walker.get_offset() as u32;
        
                        match protocol {
                            $crate::ipc::CommandProtocol::Cmif => {
                                $crate::ipc::cmif::server::write_request_command_response_on_msg_buffer(&mut ctx.ctx, $crate::result::ResultSuccess::make(), $crate::ipc::cmif::CommandType::Request);
                            },
                            $crate::ipc::CommandProtocol::Tipc => {
                                $crate::ipc::tipc::server::write_request_command_response_on_msg_buffer(&mut ctx.ctx, $crate::result::ResultSuccess::make(), 16); // TODO: is this command type actually read/used/relevant?
                            }
                        };
        
                        ctx.raw_data_walker = $crate::ipc::DataWalker::new(ctx.ctx.out_params.data_offset);
                        $( $crate::ipc::server::ResponseCommandParameter::after_response_write(&$out_param_name, &mut ctx)?; )*
        
                        Ok(())
                    }
                )*

                fn get_sf_command_metadata_table(&self) -> $crate::ipc::sf::CommandMetadataTable {
                    vec! [
                        $(
                            $crate::ipc::sf::CommandMetadata::new($rq_id, unsafe { core::mem::transmute(Self::[<sf_server_impl_ $name>] as fn(&mut Self, $crate::ipc::CommandProtocol, &mut $crate::ipc::server::ServerContext) -> $crate::result::Result<()>) }, $ver_intv)
                        ),*
                    ]
                }
            }
        }
    };
}

#[macro_export]
macro_rules! ipc_sf_define_control_interface_trait {
    (
        trait $intf:ident {
            $(
                $name:ident [$rq_id:expr, $ver_intv:expr]: ( $( $in_param_name:ident: $in_param_type:ty ),* ) => ( $( $out_param_name:ident: $out_param_type:ty ),* )
            );* $(;)* // Same as above
        }
    ) => {
        paste::paste! {
            pub trait $intf: $crate::ipc::sf::IObject {
                $(
                    #[allow(unused_parens)]
                    fn $name(&mut self, $( $in_param_name: $in_param_type ),* ) -> $crate::result::Result<( $( $out_param_type ),* )>;
        
                    #[allow(unused_assignments)]
                    #[allow(unused_parens)]
                    fn [<sf_server_impl_ $name>](&mut self, _protocol: $crate::ipc::CommandProtocol, mut ctx: &mut $crate::ipc::server::ServerContext) -> $crate::result::Result<()> {
                        // TODO: tipc support, for now force cmif
                        $crate::result_return_if!(ctx.ctx.object_info.uses_tipc_protocol(), $crate::ipc::rc::ResultInvalidProtocol);

                        ctx.raw_data_walker = $crate::ipc::DataWalker::new(ctx.ctx.in_params.data_offset);
                        $( let $in_param_name = <$in_param_type as $crate::ipc::server::RequestCommandParameter<_>>::after_request_read(&mut ctx)?; )*

                        let ( $( $out_param_name ),* ) = self.$name( $( $in_param_name ),* )?;

                        ctx.raw_data_walker = $crate::ipc::DataWalker::new(core::ptr::null_mut());
                        $( $crate::ipc::server::ResponseCommandParameter::before_response_write(&$out_param_name, &mut ctx)?; )*
                        ctx.ctx.out_params.data_size = ctx.raw_data_walker.get_offset() as u32;

                        $crate::ipc::cmif::server::write_control_command_response_on_msg_buffer(&mut ctx.ctx, $crate::result::ResultSuccess::make(), $crate::ipc::cmif::CommandType::Control);

                        ctx.raw_data_walker = $crate::ipc::DataWalker::new(ctx.ctx.out_params.data_offset);
                        $( $crate::ipc::server::ResponseCommandParameter::after_response_write(&$out_param_name, &mut ctx)?; )*

                        Ok(())
                    }
                )*

                fn get_sf_command_metadata_table(&self) -> $crate::ipc::sf::CommandMetadataTable {
                    vec! [
                        $(
                            $crate::ipc::sf::CommandMetadata::new($rq_id, unsafe { core::mem::transmute(Self::[<sf_server_impl_ $name>] as fn(&mut Self, $crate::ipc::CommandProtocol, &mut $crate::ipc::server::ServerContext) -> $crate::result::Result<()>) }, $ver_intv)
                        ),*
                    ]
                }
            }
        }
    };
}

#[macro_export]
macro_rules! ipc_sf_object_impl_default_command_metadata {
    () => {
        fn get_command_metadata_table(&self) -> $crate::ipc::sf::CommandMetadataTable {
            // Provided by the interface being implemented by this object
            self.get_sf_command_metadata_table()
        }
    };
}

// TODO: better system than using ipc_sf_object_impl_default_command_metadata!(), enforce command version when invoking it (only on client implementations, etc.), more