Skip to main content

rust2go_convert/
convert.rs

1// Copyright 2024 ihciah. All Rights Reserved.
2
3#[repr(u8)]
4#[derive(Debug, Clone, Copy)]
5pub enum MemType {
6    Primitive,
7    SimpleWrapper,
8    Complex,
9}
10
11impl MemType {
12    pub const fn next(self) -> Self {
13        match self {
14            MemType::Primitive => MemType::SimpleWrapper,
15            MemType::SimpleWrapper => MemType::Complex,
16            MemType::Complex => MemType::Complex,
17        }
18    }
19
20    pub const fn max(self, other: Self) -> Self {
21        match (self, other) {
22            (MemType::Complex, _) => MemType::Complex,
23            (MemType::SimpleWrapper, MemType::Complex) => MemType::Complex,
24            (MemType::SimpleWrapper, _) => MemType::SimpleWrapper,
25            (MemType::Primitive, r) => r,
26        }
27    }
28}
29
30#[macro_export]
31macro_rules! max_mem_type {
32    ($($ty:ty),*) => {
33        $crate::MemType::Primitive$(.max(<$ty as $crate::ToRef>::MEM_TYPE))*
34    };
35}
36
37pub struct Writer {
38    ptr: *mut u8,
39}
40
41impl Writer {
42    /// # Safety
43    /// The pointer must be valid, and it must has enough capacity.
44    #[inline]
45    pub unsafe fn new(ptr: *mut u8) -> Self {
46        Writer { ptr }
47    }
48
49    unsafe fn put<T>(&mut self, data: T) {
50        self.ptr.cast::<T>().write_unaligned(data);
51        self.ptr = self.ptr.add(std::mem::size_of::<T>());
52    }
53
54    unsafe fn reserve(&mut self, len: usize) -> Writer {
55        let fork = Writer { ptr: self.ptr };
56        self.ptr = self.ptr.add(len);
57        fork
58    }
59
60    fn as_ptr(&self) -> *const u8 {
61        self.ptr.cast()
62    }
63}
64
65pub trait ToRef {
66    const MEM_TYPE: MemType;
67
68    type Ref;
69    fn to_size(&self, acc: &mut usize);
70    fn to_ref(&self, buffer: &mut Writer) -> Self::Ref;
71
72    #[inline]
73    fn calc_size(&self) -> usize {
74        let mut size = 0;
75        self.to_size(&mut size);
76        size
77    }
78    #[inline]
79    fn calc_ref(&self) -> (Vec<u8>, Self::Ref) {
80        if matches!(Self::MEM_TYPE, MemType::Complex) {
81            let size = self.calc_size();
82            let mut buffer = Vec::with_capacity(size);
83            let ref_ = self.to_ref(&mut unsafe { Writer::new(buffer.as_ptr() as _) });
84            unsafe { buffer.set_len(size) };
85            (buffer, ref_)
86        } else {
87            let buffer = Vec::new();
88            let ref_ = self.to_ref(&mut unsafe { Writer::new(buffer.as_ptr() as _) });
89            (buffer, ref_)
90        }
91    }
92}
93
94impl<T: ToRef> ToRef for &T {
95    const MEM_TYPE: MemType = T::MEM_TYPE;
96    type Ref = T::Ref;
97
98    #[inline]
99    fn to_size(&self, acc: &mut usize) {
100        (**self).to_size(acc)
101    }
102
103    #[inline]
104    fn to_ref(&self, buffer: &mut Writer) -> Self::Ref {
105        (**self).to_ref(buffer)
106    }
107}
108
109pub trait FromRef {
110    type Ref;
111    fn from_ref(ref_: &Self::Ref) -> Self;
112}
113
114#[derive(Copy, Clone, Debug)]
115#[repr(C)]
116pub struct DataView {
117    ptr: *const (),
118    len: usize,
119}
120
121impl DataView {
122    #[inline]
123    fn new<T>(mut ptr: *const T, len: usize) -> Self {
124        if len == 0 {
125            // prevent passing NonNull::dangling() to Go when len == 0
126            ptr = std::ptr::null();
127        }
128        Self {
129            ptr: ptr.cast(),
130            len,
131        }
132    }
133}
134
135#[derive(Copy, Clone, Debug)]
136#[repr(transparent)]
137pub struct ListRef(DataView);
138
139// Owned to Ref
140// Vec<T> -> ListRef
141impl<T: ToRef> ToRef for Vec<T> {
142    const MEM_TYPE: MemType = T::MEM_TYPE.next();
143    type Ref = ListRef;
144
145    fn to_size(&self, acc: &mut usize) {
146        if matches!(Self::MEM_TYPE, MemType::Complex) {
147            *acc += self.len() * std::mem::size_of::<T::Ref>();
148            self.iter().for_each(|elem| elem.to_size(acc));
149        }
150    }
151
152    fn to_ref(&self, writer: &mut Writer) -> Self::Ref {
153        let mut data = ListRef(DataView::new(self.as_ptr(), self.len()));
154
155        if matches!(Self::MEM_TYPE, MemType::Complex) && !self.is_empty() {
156            // prevent passing NonNull::dangling() to Go when self.is_empty()
157            data.0.ptr = writer.as_ptr().cast();
158            unsafe {
159                let mut children = writer.reserve(self.len() * std::mem::size_of::<T::Ref>());
160                self.iter()
161                    .for_each(|elem| children.put(ToRef::to_ref(elem, writer)));
162            }
163        }
164        data
165    }
166}
167
168impl<T: FromRef> FromRef for Vec<T> {
169    type Ref = ListRef;
170
171    fn from_ref(ref_: &Self::Ref) -> Self {
172        if ref_.0.len == 0 {
173            return Vec::new();
174        }
175        let slice = unsafe { std::slice::from_raw_parts(ref_.0.ptr.cast(), ref_.0.len) };
176        slice.iter().map(FromRef::from_ref).collect()
177    }
178}
179
180// Owned to Ref
181// Option<T> -> ListRef
182impl<T: ToRef> ToRef for Option<T> {
183    const MEM_TYPE: MemType = T::MEM_TYPE.next();
184    type Ref = ListRef;
185
186    fn to_size(&self, acc: &mut usize) {
187        if matches!(Self::MEM_TYPE, MemType::Complex) {
188            *acc += self.as_slice().len() * std::mem::size_of::<T::Ref>();
189            self.iter().for_each(|elem| elem.to_size(acc));
190        }
191    }
192
193    fn to_ref(&self, writer: &mut Writer) -> Self::Ref {
194        let slice = self.as_slice();
195        let mut data = ListRef(DataView::new(slice.as_ptr(), slice.len()));
196
197        if matches!(Self::MEM_TYPE, MemType::Complex) && !slice.is_empty() {
198            // prevent passing NonNull::dangling() to Go when slice.is_empty()
199            data.0.ptr = writer.as_ptr().cast();
200            unsafe {
201                let mut children = writer.reserve(slice.len() * std::mem::size_of::<T::Ref>());
202                self.iter()
203                    .for_each(|elem| children.put(ToRef::to_ref(elem, writer)));
204            }
205        }
206        data
207    }
208}
209
210impl<T: FromRef> FromRef for Option<T> {
211    type Ref = ListRef;
212
213    fn from_ref(ref_: &Self::Ref) -> Self {
214        if ref_.0.len == 0 {
215            return None;
216        }
217        let slice = unsafe { std::slice::from_raw_parts(ref_.0.ptr.cast(), ref_.0.len) };
218        slice.iter().map(FromRef::from_ref).next()
219    }
220}
221
222#[derive(Copy, Clone, Debug)]
223#[repr(transparent)]
224pub struct StringRef(DataView);
225
226impl ToRef for String {
227    const MEM_TYPE: MemType = MemType::SimpleWrapper;
228    type Ref = StringRef;
229
230    #[inline]
231    fn to_size(&self, _: &mut usize) {}
232
233    #[inline]
234    fn to_ref(&self, _: &mut Writer) -> Self::Ref {
235        StringRef(DataView::new(self.as_ptr(), self.len()))
236    }
237}
238
239impl FromRef for String {
240    type Ref = StringRef;
241
242    fn from_ref(ref_: &Self::Ref) -> Self {
243        if ref_.0.len == 0 {
244            return String::new();
245        }
246        let slice = unsafe { std::slice::from_raw_parts(ref_.0.ptr.cast(), ref_.0.len) };
247        String::from_utf8_lossy(slice).into_owned()
248    }
249}
250
251macro_rules! primitive_impl {
252    ($($ty:ty),*) => {
253        $(
254            impl ToRef for $ty {
255                const MEM_TYPE: MemType = MemType::Primitive;
256                type Ref = $ty;
257
258                #[inline]
259                fn to_size(&self, _: &mut usize) {}
260
261                #[inline]
262                fn to_ref(&self, _: &mut Writer) -> Self::Ref {
263                    *self
264                }
265            }
266
267            impl FromRef for $ty {
268                type Ref = $ty;
269
270                fn from_ref(ref_: &Self::Ref) -> Self {
271                    *ref_
272                }
273            }
274        )*
275    };
276}
277
278primitive_impl!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64, bool, char);
279
280macro_rules! tuple_impl {
281    (($ty:ident, $name:tt)) => {
282        tuple_impl!(@# ($ty, $name));
283    };
284    ($(($ty:ident, $name:tt)),+) => {
285        tuple_impl!(@# $(($ty, $name)),*);
286        tuple_impl!(@! [$(($ty, $name))*]);
287    };
288    (@# $(($ty:ident, $name:tt)),*) => {
289        impl<$($ty,)*> ToRef for ($($ty,)*) where $($ty:ToRef,)* {
290            const MEM_TYPE: MemType = MemType::Primitive$(.max($ty::MEM_TYPE))*;
291            type Ref = ($($ty::Ref,)*);
292
293            fn to_size(&self, acc: &mut usize) {
294                $(self.$name.to_size(acc);)*
295            }
296
297            fn to_ref(&self, buffer: &mut Writer) -> Self::Ref {
298                (
299                    $(self.$name.to_ref(buffer),)*
300                )
301            }
302        }
303    };
304    (@! [] ($ty_l:ident, $name_l:tt) $(($ty:ident, $name:tt))*) => {
305        tuple_impl!(@~ [$(($ty, $name))*]);
306    };
307    (@! [($ty_f:ident, $name_f:tt) $(($ty:ident, $name:tt))*] $(($ty_r:ident, $name_r:tt))*) => {
308        tuple_impl!(@! [$(($ty, $name))*] ($ty_f, $name_f) $(($ty_r, $name_r))*);
309    };
310    (@~ [] $(($ty:ident, $name:tt))*) => {
311        tuple_impl!($(($ty, $name)),*);
312    };
313    (@~ [($ty_f:ident, $name_f:tt) $(($ty:ident, $name:tt))*] $(($ty_r:ident, $name_r:tt))*) => {
314        tuple_impl!(@~ [$(($ty, $name))*] ($ty_f, $name_f) $(($ty_r, $name_r))*);
315    };
316}
317
318tuple_impl!(
319    (T1, 0),
320    (T2, 1),
321    (T3, 2),
322    (T4, 3),
323    (T5, 4),
324    (T6, 5),
325    (T7, 6),
326    (T8, 7),
327    (T9, 8),
328    (T10, 9),
329    (T11, 10),
330    (T12, 11),
331    (T13, 12),
332    (T14, 13),
333    (T15, 14),
334    (T16, 15)
335);
336
337#[inline]
338fn copy_item<T>(buf: &mut Writer, item: T) {
339    unsafe { buf.put(item) };
340}
341
342trait CopyTuple {
343    fn tuple_copy_to(self, buf: &mut Writer);
344}
345
346macro_rules! copy_tuple {
347    (($ty:ident, $name:tt)) => {
348        copy_tuple!(@# ($ty, $name));
349    };
350    ($(($ty:ident, $name:tt)),+) => {
351        copy_tuple!(@# $(($ty, $name)),*);
352        copy_tuple!(@! [$(($ty, $name))*]);
353    };
354    (@# $(($ty:ident, $name:tt)),*) => {
355        impl<$($ty,)*> CopyTuple for ($($ty,)*) {
356            fn tuple_copy_to(self, buf: &mut Writer) {
357                $(copy_item(buf, self.$name);)*
358            }
359        }
360    };
361    (@! [] ($ty_l:ident, $name_l:tt) $(($ty:ident, $name:tt))*) => {
362        copy_tuple!(@~ [$(($ty, $name))*]);
363    };
364    (@! [($ty_f:ident, $name_f:tt) $(($ty:ident, $name:tt))*] $(($ty_r:ident, $name_r:tt))*) => {
365        copy_tuple!(@! [$(($ty, $name))*] ($ty_f, $name_f) $(($ty_r, $name_r))*);
366    };
367    (@~ [] $(($ty:ident, $name:tt))*) => {
368        copy_tuple!($(($ty, $name)),*);
369    };
370    (@~ [($ty_f:ident, $name_f:tt) $(($ty:ident, $name:tt))*] $(($ty_r:ident, $name_r:tt))*) => {
371        copy_tuple!(@~ [$(($ty, $name))*] ($ty_f, $name_f) $(($ty_r, $name_r))*);
372    };
373}
374
375copy_tuple!(
376    (T1, 0),
377    (T2, 1),
378    (T3, 2),
379    (T4, 3),
380    (T5, 4),
381    (T6, 5),
382    (T7, 6),
383    (T8, 7),
384    (T9, 8),
385    (T10, 9),
386    (T11, 10),
387    (T12, 11),
388    (T13, 12),
389    (T14, 13),
390    (T15, 14),
391    (T16, 15)
392);
393
394pub struct CopyStruct<T>(pub T);
395
396macro_rules! copy_struct_for_tuple {
397    (($ty:ident, $name:tt)) => {
398        copy_struct_for_tuple!(@# ($ty, $name));
399    };
400    ($(($ty:ident, $name:tt)),+) => {
401        copy_struct_for_tuple!(@# $(($ty, $name)),*);
402        copy_struct_for_tuple!(@! [$(($ty, $name))*]);
403    };
404    (@# $(($ty:ident, $name:tt)),*) => {
405        impl<$($ty,)*> ToRef for CopyStruct<($($ty,)*)> where $($ty:ToRef,)* {
406            // Complex since we need buffer
407            const MEM_TYPE: MemType = MemType::Complex;
408            type Ref = *const u8;
409
410            fn to_size(&self, acc: &mut usize) {
411                if matches!(MemType::Primitive$(.max($ty::MEM_TYPE))*, MemType::Complex) {
412                    $(self.0.$name.to_size(acc);)*
413                }
414                *acc += (0 $(+::std::mem::size_of::<$ty::Ref>())*);
415            }
416
417            fn to_ref(&self, buffer: &mut Writer) -> Self::Ref {
418                let r = ($(self.0.$name.to_ref(buffer),)*);
419                let ptr = buffer.ptr as *const u8;
420                r.tuple_copy_to(buffer);
421                ptr
422            }
423        }
424    };
425    (@! [] ($ty_l:ident, $name_l:tt) $(($ty:ident, $name:tt))*) => {
426        copy_struct_for_tuple!(@~ [$(($ty, $name))*]);
427    };
428    (@! [($ty_f:ident, $name_f:tt) $(($ty:ident, $name:tt))*] $(($ty_r:ident, $name_r:tt))*) => {
429        copy_struct_for_tuple!(@! [$(($ty, $name))*] ($ty_f, $name_f) $(($ty_r, $name_r))*);
430    };
431    (@~ [] $(($ty:ident, $name:tt))*) => {
432        copy_struct_for_tuple!($(($ty, $name)),*);
433    };
434    (@~ [($ty_f:ident, $name_f:tt) $(($ty:ident, $name:tt))*] $(($ty_r:ident, $name_r:tt))*) => {
435        copy_struct_for_tuple!(@~ [$(($ty, $name))*] ($ty_f, $name_f) $(($ty_r, $name_r))*);
436    };
437}
438
439copy_struct_for_tuple!(
440    (T1, 0),
441    (T2, 1),
442    (T3, 2),
443    (T4, 3),
444    (T5, 4),
445    (T6, 5),
446    (T7, 6),
447    (T8, 7),
448    (T9, 8),
449    (T10, 9),
450    (T11, 10),
451    (T12, 11),
452    (T13, 12),
453    (T14, 13),
454    (T15, 14),
455    (T16, 15)
456);