Skip to main content

dfhack_proto/
lib.rs

1#![warn(missing_docs)]
2#![doc = include_str!("../README.md")]
3
4use std::{fmt::Display, ops::Deref};
5
6#[allow(clippy::let_unit_value)]
7#[allow(missing_docs)]
8pub(crate) mod generated {
9    pub(crate) mod stubs;
10}
11
12/// Raw protobuf messages
13#[allow(missing_docs)]
14pub mod messages {
15    include!("generated/messages/includes.rs");
16    pub use adventure_control::*;
17    pub use dfproto::*;
18    pub use dfstockpiles::*;
19    pub use dwarf_control::*;
20    pub use itemdef_instrument::*;
21    pub use proto::enums::ui_sidebar_mode::*;
22    pub use remote_fortress_reader::*;
23}
24
25/// Stubs exposing the feature of the DFHack remote API.
26///
27/// Each stub is generated from a DFHack plugin.
28/// This module is auto-generated from DFHack sources.
29pub mod stubs {
30    pub use crate::generated::stubs::*;
31}
32
33/// Message exchanged by dfhack-remote
34pub trait Message: prost::Message + prost::Name + Default {}
35impl<T: prost::Message + prost::Name + Default> Message for T {}
36
37/// The `Channel` is the low-level exchange implementation.
38///
39/// It is in charge to serialize/deserialize messages, and exchange
40/// them with Dwarf Fortress. It is not meant to be used as is, but to be passed to
41/// It is analoguous to the gRPC channel.
42pub trait Channel {
43    /// Type of the errors raised by the stub.
44    ///
45    /// Defined by the channel implementation.
46    type TError;
47
48    /// Send a request to DFHack, and return its reply.
49    ///
50    /// # Errors
51    ///
52    /// The error type is defined by the channel implementation
53    ///
54    /// # Arguments
55    ///
56    /// * `plugin` - Name of the plugin implementing the request. Example: "RemoteFortressReader". Empty for core messages.
57    /// * `name` - Name of the method. Example: "GetDFVersion"
58    /// * `request` - Input of the method.
59    ///
60    /// # Returns
61    ///
62    /// A protobuf result type.
63    ///
64    fn request<TRequest: Message, TReply: Message>(
65        &mut self,
66        plugin: &'static str,
67        name: &'static str,
68        request: TRequest,
69    ) -> Result<Reply<TReply>, Self::TError>;
70}
71
72/// Reply to a request, it contains the actual reply value, and additional
73/// text fragments.
74pub struct Reply<T> {
75    /// The actual reply value
76    pub reply: T,
77    /// Additional text fragments received during the rpc
78    pub fragments: Vec<messages::CoreTextFragment>,
79}
80
81impl<T> Deref for Reply<T> {
82    type Target = T;
83
84    fn deref(&self) -> &Self::Target {
85        &self.reply
86    }
87}
88
89impl<T: Display> Display for Reply<T> {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        write!(f, "{}", self.reply)
92    }
93}
94
95/// Reflection for runtime inspection of the stubs.
96pub mod reflection {
97    /// Descriptor of a remote procedure call
98    ///
99    /// These are all the needed information to make a call
100    pub struct RemoteProcedureDescriptor {
101        /// Name of the RPC
102        pub name: &'static str,
103
104        /// Plugin implementing the RPC
105        ///
106        /// An empty string means the core API
107        pub plugin_name: &'static str,
108
109        /// Input type
110        ///
111        /// This is the full name of the protobuf message
112        pub input_type: String,
113
114        /// Output type
115        ///
116        /// This is the full name of the protobuf message
117        pub output_type: String,
118    }
119
120    /// Ability for a stub to list its supported methods
121    ///
122    /// This is mostly useful for testing purpose.
123    pub trait StubReflection {
124        /// List the supported remote calls
125        fn list_methods() -> Vec<RemoteProcedureDescriptor>;
126    }
127}