1// use std::Error;
2
3use serde::{de::DeserializeOwned, Serialize};
4
5/// Represents a handle to a constant or function in the Runtime.
6/// Should be constructed by calling [`Runtime::handle_for`].
7#[derive(Debug, Clone, Hash, PartialEq, Eq)]
8pub struct Handle(String);
9
10impl Handle {
11 pub fn inner(&self) -> &str {
12 &self.0
13 }
14}
15
16/// Represents an interface that can be implemented by a plugin.
17pub trait Interface
18where
19 Self: Sized,
20{
21 /// Create an interface from a given runtime.
22 /// All handles to be used by the interface should be registered and stored in `Self`.
23 fn from_runtime<T: Runtime>(runtime: &mut T) -> Option<Self>;
24}
25
26pub trait Runtime
27where
28 Self: Sized,
29{
30 /// Represents a plugin to be loaded by the runtime,
31 /// e.g. some source code + anything else needed to set up.
32 type Plugin;
33
34 /// The error type for this module.
35 /// Ideally should implement the [`std::err::Error`] trait.
36 type Error;
37
38 /// Initializes a plugin, returning a [`Runtime`] that can be queried.
39 /// Note that if you have any configuration,
40 fn init(plugin: Self::Plugin) -> Result<Self, Self::Error>;
41
42 /// Returns a top-level constant from the module.
43 /// This can be used to extract configuration information from the module, for example.
44 /// Before calling this function, get a handle into the runtime using [`handle_for`].
45 fn constant<T: DeserializeOwned>(&mut self, handle: &Handle) -> Result<T, Self::Error>;
46
47 /// Call a function defined in the module.
48 fn call<A: Serialize, R: DeserializeOwned>(
49 &mut self,
50 handle: &Handle,
51 arg: A,
52 ) -> Result<R, Self::Error>;
53
54 /// Registers a handle with the runtime.
55 /// This is a mutable item if needed, but generally
56 /// this should be an immutable operation.
57 /// Returns whether the handle exists/was successfully registered.
58 fn register_handle<T: AsRef<str>>(&mut self, name: T) -> bool;
59
60 /// Returns the handle for a given name if the handle is defined.
61 /// Will only return an error if there was an error while trying to register the handle.
62 /// This function uses [`register_handle`], no need to implement this one.
63 fn handle_for<T: AsRef<str>>(&mut self, name: T) -> Option<Handle> {
64 if self.register_handle(&name) {
65 Some(Handle(name.as_ref().to_string()))
66 } else {
67 None
68 }
69 }
70
71 /// Creates the given interface from the current module.
72 /// Returns [`Error`] if the provided plugin does not match the expected interface.
73 /// Essentially wraps the [`Interface`] trait.
74 fn as_interface<T: Interface>(&mut self) -> Option<T> {
75 Interface::from_runtime(self)
76 }
77}