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
use libc::c_void;

use self::ffi::{rust_write, rust_writter_drop, go::ffi_rust_IO_writter_new, rust_io_writter_drop};

mod ffi {
    use std::{ffi::c_uint, ptr::null, mem};

    use libc::c_void;

    use crate::util::util::ffi::Error;

    use self::go::ffi_rust_IO_writter_drop;

    use super::{GoIOWriterImpl, GoIOWritterPtr, GoIOWritter};

    pub type GoIOWrapperPtr = extern "C" fn (*const c_void, *const c_void, c_uint) -> ExecRustWriteResult;
    pub type GoIOWritterDropPtr = extern "C" fn(*const c_void);

    #[repr(C)]
    pub struct ExecRustWriteResult {
        len: c_uint,
        err: Error,
    }

    pub extern "C" fn rust_writter_drop (me: GoIOWritterPtr) {
        let rustlogger = unsafe { Box::from_raw(me as *mut GoIOWriterImpl) };
        drop(rustlogger); // なくてもいいが明示的に書く
    }

    pub extern "C" fn rust_write(rust_writter: GoIOWritterPtr, buff: *const c_void, len: c_uint) -> ExecRustWriteResult {
        let mut rustlogger = unsafe { Box::from_raw(rust_writter as *mut GoIOWriterImpl) };

        let data_slice = unsafe { std::slice::from_raw_parts(buff as *const u8, len as usize) };
        let result = match rustlogger.rust_writter.write(data_slice) {
            Ok(len) => ExecRustWriteResult {
                len: len as c_uint,
                err: null(),
            },
            Err(err) => {
                let err = match std::ffi::CString::new(err.to_string()) {
                    Ok(v) => v.as_ptr(),
                    Err(e) => {
                        println!("rust write err defer null error: {e}");
                        null()
                    }
                };
                ExecRustWriteResult {
                    len: 0, err: err
                }
            }
        };
        mem::forget(rustlogger);
        result
    }

    pub mod go {
        use crate::util::go_iowritter::GoIOWritterPtr;

        use super::{GoIOWrapperPtr, GoIOWritterDropPtr};

        extern "C" {
            pub fn ffi_rust_IO_writter_new(wrapperPtr: GoIOWrapperPtr, writterPtr: GoIOWritterPtr, dropFuncPtr: GoIOWritterDropPtr) -> GoIOWritterPtr;
            pub fn ffi_rust_IO_writter_drop(writterPtr: GoIOWritterPtr);
        }
    }

    pub(crate) fn rust_io_writter_drop (writter: &mut GoIOWritter) {
        unsafe { ffi_rust_IO_writter_drop(writter.go_io_writter_ptr) };
    }
}

pub(crate) type GoIOWritterPtr = *const c_void;

struct GoIOWriterImpl {
    rust_writter: Box<dyn std::io::Write>,
}

impl GoIOWriterImpl {
    pub fn new <T: std::io::Write + 'static>(writter: T) -> *const c_void {
        let me = Box::new(Self {
            rust_writter: Box::new(writter)
        });
        let myptr = Box::into_raw(me) as *const c_void;
        let result = unsafe { ffi_rust_IO_writter_new(rust_write, myptr, rust_writter_drop) };
        if result.is_null() {
            panic!("go: ffi_rust_IO_writter_new error");
        }
        result
    }
}

pub struct GoIOWritter {
    pub(crate) go_io_writter_ptr: GoIOWritterPtr,
}

impl GoIOWritter {
    pub fn new <T: std::io::Write + 'static>(writter: T) -> Self {
        Self {
            go_io_writter_ptr: GoIOWriterImpl::new(writter),
        }
    }
}

impl Drop for GoIOWritter {
    fn drop(&mut self) {
        rust_io_writter_drop(self);
    }
}