-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathlib.rs
More file actions
186 lines (160 loc) · 6.15 KB
/
Copy pathlib.rs
File metadata and controls
186 lines (160 loc) · 6.15 KB
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#![no_std]
use core::cell::{Cell, RefCell};
use demo_walker as walker;
use sails::prelude::*;
mod chaos;
mod counter;
mod dog;
mod inheritance;
mod mammal;
mod override_generics;
mod ping;
mod references;
mod this_that;
mod validator;
mod value_fee;
// Dog data is stored as a global variable. However, it has exactly the same lifetime
// the Counter data incapsulated in the program itself, i.e. there are no any benefits
// of using a global variable here. It is just a demonstration of how to use global variables.
static mut DOG_DATA: Option<RefCell<walker::WalkerData>> = None;
#[allow(static_mut_refs)]
fn dog_data() -> &'static RefCell<walker::WalkerData> {
unsafe {
DOG_DATA
.as_ref()
.unwrap_or_else(|| panic!("`Dog` data should be initialized first"))
}
}
// `DemoProgram` is the on-chain program state. The `#[program]` macro emits a
// hidden `wasm` submodule that holds it as `static mut PROGRAM: Option<DemoProgram> = None;`
// and wires the WASM `init`/`handle` entry points to construct, then borrow it
// for every incoming message. So fields declared here live as long as the
// program is deployed on the network.
pub struct DemoProgram {
// Counter data has the same lifetime as the program itself, i.e. it will
// live as long as the program is available on the network.
counter_data: RefCell<counter::CounterData>,
validator_data: RefCell<validator::ValidatorData>,
ref_data: Cell<u8>,
}
#[program(payable)]
impl DemoProgram {
#[allow(clippy::should_implement_trait)]
/// Program constructor (called once at the very beginning of the program lifetime)
pub fn default() -> Self {
unsafe {
DOG_DATA = Some(RefCell::new(walker::WalkerData::new(
Default::default(),
Default::default(),
)));
}
override_generics::init_generic_data(Default::default());
Self {
counter_data: RefCell::new(counter::CounterData::new(Default::default())),
validator_data: RefCell::new(validator::ValidatorData::new()),
ref_data: Cell::new(42),
}
}
/// Another program constructor (called once at the very beginning of the program lifetime)
#[export(unwrap_result)]
pub fn new(counter: Option<u32>, dog_position: Option<(i32, i32)>) -> Result<Self, String> {
unsafe {
let dog_position = dog_position.unwrap_or_default();
DOG_DATA = Some(RefCell::new(walker::WalkerData::new(
dog_position.0,
dog_position.1,
)));
}
override_generics::init_generic_data(Default::default());
Ok(Self {
counter_data: RefCell::new(counter::CounterData::new(counter.unwrap_or_default())),
validator_data: RefCell::new(validator::ValidatorData::new()),
ref_data: Cell::new(42),
})
}
#[export(unwrap_result)]
pub fn new_with_error(value: u32) -> Result<Self, String> {
if value == 0 {
return Err("Constructor failed".to_string());
}
unsafe {
DOG_DATA = Some(RefCell::new(walker::WalkerData::new(0, 0)));
}
override_generics::init_generic_data(Default::default());
Ok(Self {
counter_data: RefCell::new(counter::CounterData::new(value)),
validator_data: RefCell::new(validator::ValidatorData::new()),
ref_data: Cell::new(42),
})
}
// Exposing service with overriden route
#[export(route = "ping_pong", unwrap_result)]
pub fn ping(&self) -> Result<ping::PingService, String> {
Ok(ping::PingService::default())
}
// Exposing another service
pub fn counter(&self) -> counter::CounterService<&RefCell<counter::CounterData>> {
counter::CounterService::new(&self.counter_data)
}
// Exposing yet another service
pub fn dog(&self) -> dog::DogService {
dog::DogService::new(walker::WalkerService::new(dog_data()))
}
pub fn references(&self) -> references::ReferenceService<'_> {
references::ReferenceService::new(&self.ref_data, "demo")
}
pub fn this_that(&self) -> this_that::MyService {
this_that::MyService::default()
}
pub fn value_fee(&self) -> value_fee::FeeService {
value_fee::FeeService::new(10_000_000_000_000)
}
pub fn validator(&self) -> validator::Validator<&RefCell<validator::ValidatorData>> {
validator::Validator::new(&self.validator_data)
}
pub fn chaos(&self) -> chaos::ChaosService {
chaos::ChaosService
}
pub fn chain(&self) -> inheritance::ChainService {
inheritance::ChainService::new(dog::DogService::new(walker::WalkerService::new(dog_data())))
}
pub fn override_generics(&self) -> override_generics::ChildService<u8> {
override_generics::ChildService::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use sails::gstd::services::Exposure;
// Test program constructor and exposed service
// Mock `Syscall` to simulate the environment
#[tokio::test]
async fn program_service_exposure() {
// Arrange
let program = DemoProgram::new(Some(42), None).unwrap();
// First call
let message_value = 100_000_000_000_000;
Syscall::with_message_value(message_value);
Syscall::with_message_id(MessageId::from(1));
let mut service_exposure = program.value_fee();
let (_, value) = service_exposure
.do_something_and_take_fee()
.unwrap()
.to_tuple();
// Assert
assert_eq!(6, service_exposure.route_idx());
assert_eq!(value, message_value - 10_000_000_000_000);
// Next call
Syscall::with_message_value(0);
Syscall::with_message_id(MessageId::from(2));
let mut service_exposure = program.counter();
let mut emitter = service_exposure.emitter();
let data = service_exposure.add(10);
// Assert
assert_eq!(2, service_exposure.route_idx());
assert_eq!(52, data);
let events = emitter.take_events();
assert_eq!(events.len(), 1);
assert_eq!(events[0], counter::CounterEvents::Added(10));
}
}