1use crate::error::NylonRingHostError;
4use crate::stream_channel::{StreamChannelReceiver, StreamSender};
5use crate::{PluginCallGuard, context, context::HostContext};
6use dashmap::DashMap;
7use nylon_ring::NrStatus;
8use rustc_hash::FxBuildHasher;
9use std::collections::HashMap;
10use std::sync::Arc;
11use std::task::Waker;
12
13pub type Result<T> = std::result::Result<T, NylonRingHostError>;
15
16#[derive(Debug)]
18pub(crate) enum Pending {
19 Unary(UnaryPending),
20 Stream(StreamSender),
21}
22
23#[derive(Debug)]
25pub(crate) enum UnaryPending {
26 Waiting {
27 waker: Option<Waker>,
28 lease: Option<Vec<u8>>,
32 },
33 Ready(NrStatus, ResponsePayload),
34}
35
36#[derive(Debug)]
44pub(crate) struct ForeignBytes {
45 ptr: *const u8,
46 len: usize,
47 owner_ctx: *mut std::ffi::c_void,
48 release: Option<unsafe extern "C" fn(*mut std::ffi::c_void, *const u8, u64)>,
49}
50
51unsafe impl Send for ForeignBytes {}
54unsafe impl Sync for ForeignBytes {}
55
56impl ForeignBytes {
57 pub(crate) fn from_abi(payload: nylon_ring::NrOwnedBytes) -> Self {
59 Self {
60 ptr: payload.ptr,
61 len: payload.len as usize,
62 owner_ctx: payload.owner_ctx,
63 release: payload.release,
64 }
65 }
66
67 pub(crate) fn as_slice(&self) -> &[u8] {
68 if self.ptr.is_null() || self.len == 0 {
69 return &[];
70 }
71 unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
74 }
75}
76
77impl Drop for ForeignBytes {
78 fn drop(&mut self) {
79 if let Some(release) = self.release {
80 unsafe { release(self.owner_ctx, self.ptr, self.len as u64) };
83 }
84 }
85}
86
87#[derive(Debug)]
89pub(crate) enum ResponsePayload {
90 Owned(Vec<u8>),
91 Foreign(ForeignBytes),
92}
93
94impl ResponsePayload {
95 pub(crate) fn as_slice(&self) -> &[u8] {
96 match self {
97 Self::Owned(data) => data,
98 Self::Foreign(foreign) => foreign.as_slice(),
99 }
100 }
101
102 pub(crate) fn into_vec(self) -> Vec<u8> {
105 match self {
106 Self::Owned(data) => data,
107 Self::Foreign(foreign) => foreign.as_slice().to_vec(),
108 }
109 }
110}
111
112pub struct ResponseBytes {
119 payload: ResponsePayload,
120 _guard: Option<PluginCallGuard>,
124}
125
126impl ResponseBytes {
127 pub(crate) fn new(payload: ResponsePayload, guard: Option<PluginCallGuard>) -> Self {
128 Self {
129 payload,
130 _guard: guard,
131 }
132 }
133
134 pub fn into_vec(self) -> Vec<u8> {
137 let Self { payload, _guard } = self;
139 payload.into_vec()
140 }
141}
142
143impl std::ops::Deref for ResponseBytes {
144 type Target = [u8];
145
146 fn deref(&self) -> &[u8] {
147 self.payload.as_slice()
148 }
149}
150
151impl AsRef<[u8]> for ResponseBytes {
152 fn as_ref(&self) -> &[u8] {
153 self.payload.as_slice()
154 }
155}
156
157impl std::fmt::Debug for ResponseBytes {
158 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159 f.debug_struct("ResponseBytes")
160 .field("len", &self.payload.as_slice().len())
161 .field(
162 "foreign",
163 &matches!(self.payload, ResponsePayload::Foreign(_)),
164 )
165 .finish()
166 }
167}
168
169impl UnaryPending {
170 pub(crate) const fn waiting() -> Self {
171 Self::Waiting {
172 waker: None,
173 lease: None,
174 }
175 }
176}
177
178#[derive(Debug)]
180pub struct StreamFrame {
181 pub status: NrStatus,
182 pub data: Vec<u8>,
183}
184
185pub struct StreamReceiver {
189 inner: StreamChannelReceiver,
190 host_ctx: Option<Arc<HostContext>>,
194 sid: u64,
195 call_guard: Option<PluginCallGuard>,
196}
197
198impl StreamReceiver {
199 pub(crate) fn new(
200 inner: StreamChannelReceiver,
201 host_ctx: Option<Arc<HostContext>>,
202 sid: u64,
203 call_guard: Option<PluginCallGuard>,
204 ) -> Self {
205 debug_assert!(
206 host_ctx.is_some() || call_guard.is_some(),
207 "stream receiver needs a context source"
208 );
209 Self {
210 inner,
211 host_ctx,
212 sid,
213 call_guard,
214 }
215 }
216
217 fn host_ctx(&self) -> &HostContext {
218 match (&self.call_guard, &self.host_ctx) {
219 (Some(guard), _) => &guard.plugin().host_ctx,
220 (None, Some(host_ctx)) => host_ctx,
221 (None, None) => unreachable!("checked at construction"),
222 }
223 }
224
225 pub async fn recv(&mut self) -> Option<StreamFrame> {
227 self.inner.recv().await
228 }
229}
230
231impl Drop for StreamReceiver {
232 fn drop(&mut self) {
233 context::cleanup_sid(self.host_ctx(), self.sid);
238 self.inner.recycle();
239 }
240}
241
242pub(crate) type FastPendingMap = DashMap<u64, Pending, FxBuildHasher>;
244
245pub(crate) type FastStateMap = DashMap<u64, HashMap<String, Vec<u8>>, FxBuildHasher>;
247
248pub(crate) struct UnaryResultSlot {
250 pub(crate) sid: u64,
251 pub(crate) result: Option<(NrStatus, Vec<u8>)>,
252 pub(crate) lease: Option<Vec<u8>>,
254}