1/*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16//! This create implement the IPC proxy and stub for "example.calc.ipc.ICalcService"
17
18extern crate ipc_rust;
19
20mod access_token;
21
22use ipc_rust::{
23    IRemoteBroker, IRemoteObj, RemoteStub, IpcResult,
24    IpcStatusCode, RemoteObj, define_remote_object, FIRST_CALL_TRANSACTION,
25};
26use ipc_rust::{
27    MsgParcel, BorrowedMsgParcel,
28};
29use std::convert::{TryFrom, TryInto};
30pub use access_token::init_access_token;
31
32/// add num1 + num2
33pub fn add(num1: &i32, num2: &i32) -> i32 {
34    num1 + num2
35}
36
37/// sub num1 + num2
38pub fn sub(num1: &i32, num2: &i32) -> i32 {
39    num1 - num2
40}
41
42/// mul num1 + num2
43pub fn mul(num1: &i32, num2: &i32) -> i32 {
44    num1 * num2
45}
46
47/// div num1 + num2
48pub fn div(num1: &i32, num2: &i32) -> i32 {
49    match num2 {
50        0 => {
51            println!("Zero cannot be divided");
52            -1
53        },
54        _ => num1 / num2,
55    }
56}
57
58/// SA ID for "example.calc.ipc.ICalcService"
59pub const EXAMPLE_IPC_CALC_SERVICE_ID: i32 = 1118;
60
61/// Function code of ICalcService
62pub enum ICalcCode {
63    /// add
64    CodeAdd = FIRST_CALL_TRANSACTION,
65    /// sub
66    CodeSub,
67    /// mul
68    CodeMul,
69    /// div
70    CodeDiv,
71}
72
73impl TryFrom<u32> for ICalcCode {
74    type Error = IpcStatusCode;
75    fn try_from(code: u32) -> IpcResult<Self> {
76        match code {
77            _ if code == ICalcCode::CodeAdd as u32 => Ok(ICalcCode::CodeAdd),
78            _ if code == ICalcCode::CodeSub as u32 => Ok(ICalcCode::CodeSub),
79            _ if code == ICalcCode::CodeMul as u32 => Ok(ICalcCode::CodeMul),
80            _ if code == ICalcCode::CodeDiv as u32 => Ok(ICalcCode::CodeDiv),
81            _ => Err(IpcStatusCode::Failed),
82        }
83    }
84}
85
86/// Function between proxy and stub of ICalcService
87pub trait ICalc: IRemoteBroker {
88    /// Calc add num1 + num2
89    fn add(&self, num1: i32, num2: i32) -> IpcResult<i32>;
90    /// Calc sub num1 + num2
91    fn sub(&self, num1: i32, num2: i32) -> IpcResult<i32>;
92    /// Calc mul num1 + num2
93    fn mul(&self, num1: i32, num2: i32) -> IpcResult<i32>;
94    /// Calc div num1 + num2
95    fn div(&self, num1: i32, num2: i32) -> IpcResult<i32>;
96}
97
98fn on_icalc_remote_request(stub: &dyn ICalc, code: u32, data: &BorrowedMsgParcel,
99    reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
100    match code.try_into()? {
101        ICalcCode::CodeAdd => {
102            let num1: i32 = data.read().expect("Failed to read num1 in addition operation");
103            let num2: i32 = data.read().expect("Failed to read num2 in addition operation");
104            let ret = stub.add(num1, num2)?;
105            reply.write(&ret)?;
106            Ok(())
107        }
108        ICalcCode::CodeSub => {
109            let num1: i32 = data.read().expect("Failed to read num1 in subtraction operation");
110            let num2: i32 = data.read().expect("Failed to read num1 in subtraction operation");
111            let ret = stub.sub(num1, num2)?;
112            reply.write(&ret)?;
113            Ok(())
114        }
115        ICalcCode::CodeMul => {
116            let num1: i32 = data.read().expect("Failed to read num1 in multiplication operation");
117            let num2: i32 = data.read().expect("Failed to read num1 in multiplication operation");
118            let ret = stub.mul(num1, num2)?;
119            reply.write(&ret)?;
120            Ok(())
121        }
122        ICalcCode::CodeDiv => {
123            let num1: i32 = data.read().expect("Failed to read num1 in division  operation");
124            let num2: i32 = data.read().expect("Failed to read num1 in division  operation");
125            let ret = stub.div(num1, num2)?;
126            reply.write(&ret)?;
127            Ok(())
128        }
129    }
130}
131
132define_remote_object!(
133    ICalc["example.calc.ipc.ICalcService"] {
134        stub: CalcStub(on_icalc_remote_request),
135        proxy: CalcProxy,
136    }
137);
138
139// Make RemoteStub<CalcStub> object can call ICalc function directly.
140impl ICalc for RemoteStub<CalcStub> {
141    fn add (&self, num1: i32, num2: i32) -> IpcResult<i32> {
142        self.0.add(num1, num2)
143    }
144    fn sub (&self, num1: i32, num2: i32) -> IpcResult<i32> {
145        self.0.sub(num1, num2)
146    }
147    fn mul (&self, num1: i32, num2: i32) -> IpcResult<i32> {
148        self.0.mul(num1, num2)
149    }
150    fn div (&self, num1: i32, num2: i32) -> IpcResult<i32> {
151        self.0.div(num1, num2)
152    }
153}
154
155impl ICalc for CalcProxy {
156    fn add(&self, num1: i32, num2: i32) -> IpcResult<i32> {
157        let mut data = MsgParcel::new().expect("MsgParcel should success");
158        data.write(&num1)?;
159        data.write(&num2)?;
160        let reply = self.remote.send_request(ICalcCode::CodeAdd as u32,
161            &data, false)?;
162        let ret: i32 = reply.read().expect("need reply i32");
163        Ok(ret)
164    }
165    fn sub(&self, num1: i32, num2: i32) -> IpcResult<i32> {
166        let mut data = MsgParcel::new().expect("MsgParcel should success");
167        data.write(&num1)?;
168        data.write(&num2)?;
169        let reply = self.remote.send_request(ICalcCode::CodeSub as u32,
170            &data, false)?;
171        let ret: i32 = reply.read().expect("need reply i32");
172        Ok(ret)
173    }
174    fn mul(&self, num1: i32, num2: i32) -> IpcResult<i32> {
175        let mut data = MsgParcel::new().expect("MsgParcel should success");
176        data.write(&num1)?;
177        data.write(&num2)?;
178        let reply = self.remote.send_request(ICalcCode::CodeMul as u32,
179            &data, false)?;
180        let ret: i32 = reply.read().expect("need reply i32");
181        Ok(ret)
182    }
183    fn div(&self, num1: i32, num2: i32) -> IpcResult<i32> {
184        let mut data = MsgParcel::new().expect("MsgParcel should success");
185        data.write(&num1)?;
186        data.write(&num2)?;
187        let reply = self.remote.send_request(ICalcCode::CodeDiv as u32,
188            &data, false)?;
189        let ret: i32 = reply.read().expect("need reply i32");
190        Ok(ret)
191    }
192}