Files
simple-rust-tests/__ffi/abi_stable_crates/plugin_0/src/lib.rs

162 lines
4.1 KiB
Rust

/*!
This is an `implementation crate`,
It exports the root module(a struct of function pointers) required by the
`example_0_interface`(the `interface crate`).
*/
use std::collections::HashSet;
use abi_stable::{
export_root_module,
sabi_extern_fn,
external_types::crossbeam_channel::RSender,
prefix_type::PrefixTypeTrait,
sabi_trait::prelude::TU_Opaque,
std_types::{RStr,RVec, RString,RResult,ROk},
};
use example_interface::{
AsyncCommand,
ApplicationMut,
CommandDescription,
Error as AppError,
Plugin,PluginType,PluginId,PluginMod,PluginMod_Ref,
Plugin_TO,
utils::process_command,
};
use core_extensions::{SelfOps,StringExt};
use serde::{Serialize,Deserialize};
///////////////////////////////////////////////////////////////////////////////////
/// Exports the root module of this library.
///
/// This code isn't run until the layout of the type it returns is checked.
#[export_root_module]
fn instantiate_root_module()->PluginMod_Ref{
PluginMod {
new,
}.leak_into_prefix()
}
//////////////////////////////////////////////////////////////////////////////////////
/// Instantiates the plugin.
#[sabi_extern_fn]
pub fn new(_sender:RSender<AsyncCommand>,plugin_id:PluginId) -> RResult<PluginType,AppError> {
let this=TextMunging{
plugin_id,
};
ROk(Plugin_TO::from_value(this,TU_Opaque))
}
//////////////////////////////////////////////////////////////////////////////////////
#[derive(Debug,Serialize,Deserialize)]
pub enum ProcessTextCmd{
Rot13(String),
CapitalizeWords{
text:String,
words:HashSet<String>
},
}
#[derive(Debug,Serialize,Deserialize)]
pub enum ReturnValue{
Rot13(String),
CapitalizeWords(String),
}
//////////////////////////////////////////////////////////////////////////////////////
fn run_command_inner(
_this:&mut TextMunging,
command:ProcessTextCmd,
_app:ApplicationMut<'_>,
)->Result<ReturnValue,AppError>{
match command {
ProcessTextCmd::Rot13(text)=>{
pub fn rot13(this:char)-> char{
match this{
v@'a'..='z'=>
((((v as u8 - b'a')+13)%26)+b'a')as char,
v@'A'..='Z'=>
((((v as u8 - b'A')+13)%26)+b'A')as char,
v=>v
}
}
text.chars()
.map(rot13)
.collect::<String>()
.piped(ReturnValue::Rot13)
}
ProcessTextCmd::CapitalizeWords{text,words}=>{
let mut buffer=String::with_capacity(10);
for kv in text.split_while(|c|c.is_alphabetic()) {
let str_=kv.str;
let is_a_word=kv.key;
if is_a_word && words.contains(str_) {
buffer.extend(str_.chars().flat_map(char::to_uppercase));
}else{
buffer.push_str(str_);
}
}
ReturnValue::CapitalizeWords(buffer)
}
}.piped(Ok)
}
//////////////////////////////////////////////////////////////////////////////////////
struct TextMunging{
plugin_id:PluginId,
}
impl Plugin for TextMunging {
fn json_command(
&mut self,
command: RStr<'_>,
app:ApplicationMut<'_>,
)->RResult<RString,AppError>{
process_command(self,command,|this,command:ProcessTextCmd|{
run_command_inner(this,command,app)
})
}
fn plugin_id(&self)->&PluginId{
&self.plugin_id
}
fn list_commands(&self)->RVec<CommandDescription>{
vec![
CommandDescription::from_literals(
"Rot13",
"Uses the rot13 algorithm to hide spoilers in plain text."
),
CommandDescription::from_literals(
"CapitalizeWords",
"Capitalizes the words specified in words.\n\
\n\
Command parans:\n\
{\"text\":\"text here\",words:[\"word0\",\"word1\"]}",
),
].into()
}
fn close(self,_app:ApplicationMut<'_>){}
}