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
//! Plugin-layer controller trait.
//!
//! `PluginController` is the host-visible interface that every backend
//! (native Rust / WASM / Rhai / PyO3 / ...) implements. A controller
//! receives an [`TickInput`] snapshot at each sample tick and returns
//! an optional logical [`Command`] to be applied by the host's actuator bridge.
//!
//! This is separate from the existing
//! [`crate::control::DiscreteController`] trait on purpose: the legacy
//! trait is parameterised over a concrete `type Command` (e.g.
//! `Vector3<f64>`) and takes `(attitude, orbit, epoch)` as positional
//! arguments. The plugin trait fixes `Command` to the
//! [`super::Command`] struct and bundles all inputs into a single
//! `TickInput` struct so that WASM guests can share the same shape
//! with native implementations. A future phase may unify the two once
//! every native controller has migrated; Phase P0.5 deliberately keeps
//! them side by side so that no existing oracle tests have to change.
//!
//! See DESIGN.md Phase P, D3 ("trait 構造: 既存 DiscreteController を
//! 拡張して 1 trait に統一") for the long-term plan — P0.5 introduces
//! `PluginController` as the forward-compatible target shape.
use Command;
use PluginError;
use TickInput;
/// A controller backend exposed through the plugin layer.
///
/// Implementors are either native Rust controllers (`BdotFiniteDiff`,
/// `InertialPdController`, ...) or guest runtimes wrapping a WASM
/// component / Rhai script / Python callable. In both cases the
/// contract is the same: given a tick input, optionally produce a command.
///
/// `Send` is required so individual satellite simulations (each
/// holding its own controller instance) can be driven on worker
/// threads. `Sync` is NOT required — `wasmtime::Store` is `!Sync`, and
/// the orts spacecraft lifecycle is "1 controller = 1 satellite", so
/// there is no legitimate need to share a single controller across
/// threads concurrently.