I’m trying to integrate a text-to-speech system that isn’t threadsafe. My crate for TTS calls out to external APIs, and doesn’t implement std::marker::Send
. What I essentially need is an application-wide TTS
instance that may be used from multiple systems–game-related systems for sending speech descriptions of events, input systems for speaking responses to commands, UI systems for speaking when items get/lose focus or change, etc. The worst that can happen if multiple systems access TTS simultaneously is that messages get pre-empted, and that’s usually desirable anyway.
Because I don’t implement Send
, I can’t store the TTS
instance as a resource. My next hope was that I could create a TTSSystem
that managed the single TTS
instance, then opened an event channel that received and processed events–essentially an actor. Unfortunately I can’t even do this:
struct TTSSystem(tts::TTS);
impl TTSSystem {
fn new() -> Result<TTSSystem, tts::Error> {
let tts = tts::TTS::default()?;
Ok(TTSSystem(tts))
}
}
impl<'s> System<'s> for TTSSystem {
type SystemData = ();
fn run(&mut self, _: Self::SystemData) {
}
}
struct AccessibilityBundle;
impl<'a, 'b> bundle::SystemBundle<'a, 'b> for AccessibilityBundle {
fn build(self, builder: &mut DispatcherBuilder<'a, 'b>) -> bundle::Result<()> {
let tts = TTSSystem::new()?;
builder.add(tts, "tts_system", &[]);
Ok(())
}
}
because even that level of abstraction without Send
is rejected.
I understand that Rust is trying to prevent me from shooting myself in the foot here, but does Amethyst really not offer an escape hatch for creating a singleton system to guard access to a non-threadsafe API?
Thanks.