atri_plugin 0.9.0

AtriPlugin
Documentation
use crate::message::at::At;
use crate::message::face::Face;
use crate::message::image::Image;
use crate::message::meta::{Anonymous, MessageMetadata, Reply};
use crate::message::{MessageChain, MessageElement};
use atri_ffi::ffi::ForFFI;
use atri_ffi::message::meta::{
    FFIAnonymous, FFIMessageMetadata, FFIReply, ANONYMOUS_FLAG, NONE_META, REPLY_FLAG,
};
use atri_ffi::message::{
    FFIAt, FFIFace, FFIMessageChain, FFIMessageElement, MessageElementFlag, MessageElementUnion,
};
use atri_ffi::{RustString, RustVec};
use std::mem::{ManuallyDrop, MaybeUninit};

impl ForFFI for MessageChain {
    type FFIValue = FFIMessageChain;

    fn into_ffi(self) -> Self::FFIValue {
        let v: Vec<FFIMessageElement> = self
            .elements
            .into_iter()
            .map(MessageElement::into_ffi)
            .collect();

        let raw = RustVec::from(v);
        FFIMessageChain {
            meta: self.meta.into_ffi(),
            inner: raw,
        }
    }

    fn from_ffi(ffi: Self::FFIValue) -> Self {
        let v = ffi.inner.into_vec();
        let value = v.into_iter().map(MessageElement::from_ffi).collect();
        Self {
            meta: MessageMetadata::from_ffi(ffi.meta),
            elements: value,
        }
    }
}

impl ForFFI for MessageElement {
    type FFIValue = FFIMessageElement;

    fn into_ffi(self) -> Self::FFIValue {
        match self {
            MessageElement::Text(s) => FFIMessageElement {
                t: MessageElementFlag::Text.value(),
                union: MessageElementUnion {
                    text: ManuallyDrop::new(RustString::from(s)),
                },
            },
            MessageElement::Image(img) => FFIMessageElement {
                t: MessageElementFlag::Image.value(),
                union: MessageElementUnion {
                    image: ManuallyDrop::new(img.0),
                },
            },
            MessageElement::At(At { target, display }) => FFIMessageElement {
                t: MessageElementFlag::At.value(),
                union: MessageElementUnion {
                    at: ManuallyDrop::new({
                        let display = RustString::from(display);
                        FFIAt { target, display }
                    }),
                },
            },
            MessageElement::AtAll => FFIMessageElement {
                t: MessageElementFlag::AtAll.value(),
                union: MessageElementUnion { at_all: () },
            },
            MessageElement::Face(Face { index, name }) => FFIMessageElement {
                t: MessageElementFlag::Face.value(),
                union: MessageElementUnion {
                    face: ManuallyDrop::new({
                        let name = RustString::from(name);
                        FFIFace { index, name }
                    }),
                },
            },
            MessageElement::Unknown(ma) => FFIMessageElement {
                t: 255,
                union: MessageElementUnion {
                    unknown: ManuallyDrop::new(ma),
                },
            },
        }
    }

    fn from_ffi(value: Self::FFIValue) -> Self {
        unsafe {
            match MessageElementFlag::try_from(value.t).unwrap_or_else(|t| {
                panic!(
                    "Unknown message flag: {}, please update your atri_plugin crate",
                    t
                )
            }) {
                MessageElementFlag::Text => {
                    Self::Text(ManuallyDrop::into_inner(value.union.text).into())
                }
                MessageElementFlag::Image => {
                    Self::Image(Image(ManuallyDrop::into_inner(value.union.image)))
                }
                MessageElementFlag::At => {
                    let FFIAt { target, display } = ManuallyDrop::into_inner(value.union.at);
                    let display = String::from(display);

                    Self::At(At { target, display })
                }
                MessageElementFlag::AtAll => Self::AtAll,
                MessageElementFlag::Face => {
                    let FFIFace { index, name } = ManuallyDrop::into_inner(value.union.face);
                    let name = String::from(name);

                    Self::Face(Face { index, name })
                }
                MessageElementFlag::Unknown => {
                    Self::Unknown(ManuallyDrop::into_inner(value.union.unknown))
                }
            }
        }
    }
}

impl ForFFI for At {
    type FFIValue = FFIAt;

    fn into_ffi(self) -> Self::FFIValue {
        let At { target, display } = self;

        FFIAt {
            target,
            display: RustString::from(display),
        }
    }

    fn from_ffi(value: Self::FFIValue) -> Self {
        let FFIAt { target, display } = value;

        Self {
            target,
            display: String::from(display),
        }
    }
}

impl ForFFI for MessageMetadata {
    type FFIValue = FFIMessageMetadata;

    fn into_ffi(self) -> Self::FFIValue {
        let Self {
            seqs,
            rands,
            time,
            sender,
            anonymous,
            reply,
        } = self;

        let mut flags = NONE_META;

        let mut ffi_anonymous = MaybeUninit::uninit();
        if let Some(ano) = anonymous {
            flags |= ANONYMOUS_FLAG;
            ffi_anonymous.write(ano.into_ffi());
        }

        let mut ffi_reply = MaybeUninit::uninit();
        if let Some(reply) = reply {
            flags |= REPLY_FLAG;
            ffi_reply.write(reply.into_ffi());
        }

        FFIMessageMetadata {
            seqs: seqs.into(),
            rands: rands.into(),
            time,
            sender,
            flags,
            anonymous: ffi_anonymous,
            reply: ffi_reply,
        }
    }

    fn from_ffi(ffi: Self::FFIValue) -> Self {
        let FFIMessageMetadata {
            seqs,
            rands,
            time,
            sender,
            flags,
            reply,
            anonymous,
        } = ffi;

        unsafe {
            Self {
                seqs: seqs.into_vec(),
                rands: rands.into_vec(),
                time,
                sender,
                anonymous: if flags & ANONYMOUS_FLAG != 0 {
                    Some(Anonymous::from_ffi(anonymous.assume_init()))
                } else {
                    None
                },
                reply: if flags & REPLY_FLAG != 0 {
                    Some(Reply::from_ffi(reply.assume_init()))
                } else {
                    None
                },
            }
        }
    }
}

impl ForFFI for Reply {
    type FFIValue = FFIReply;

    fn into_ffi(self) -> Self::FFIValue {
        let Self {
            reply_seq,
            sender,
            time,
            elements,
        } = self;

        let ffi_value: Vec<FFIMessageElement> =
            elements.into_iter().map(|value| value.into_ffi()).collect();
        let raw = RustVec::from(ffi_value);

        FFIReply {
            reply_seq,
            sender,
            time,
            elements: raw,
        }
    }

    fn from_ffi(ffi: Self::FFIValue) -> Self {
        let FFIReply {
            reply_seq,
            sender,
            time,
            elements,
        } = ffi;

        let v = elements.into_vec();
        let value: Vec<MessageElement> = v.into_iter().map(MessageElement::from_ffi).collect();

        Self {
            reply_seq,
            sender,
            time,
            elements: value,
        }
    }
}

impl ForFFI for Anonymous {
    type FFIValue = FFIAnonymous;

    fn into_ffi(self) -> Self::FFIValue {
        let Self {
            anon_id,
            nick,
            portrait_index,
            bubble_index,
            expire_time,
            color,
        } = self;

        let anon_id = RustVec::from(anon_id);
        let nick = RustString::from(nick);
        let color = RustString::from(color);

        FFIAnonymous {
            anon_id,
            nick,
            portrait_index,
            bubble_index,
            expire_time,
            color,
        }
    }

    fn from_ffi(ffi: Self::FFIValue) -> Self {
        let FFIAnonymous {
            anon_id,
            nick,
            portrait_index,
            bubble_index,
            expire_time,
            color,
        } = ffi;

        let anon_id = anon_id.into_vec();
        let nick = String::from(nick);
        let color = String::from(color);

        Self {
            anon_id,
            nick,
            portrait_index,
            bubble_index,
            expire_time,
            color,
        }
    }
}