Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support serenity simd_json #105

Merged
merged 21 commits into from
Jul 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
- Windows
- driver only
- gateway only
- simd json

include:
- name: beta
Expand All @@ -55,6 +56,10 @@ jobs:
- name: gateway only
features: serenity-rustls
dont-test: true
- name: simd json
features: simd-json serenity-rustls driver gateway serenity/simd_json
rustflags: -C target-cpu=native
dont-test: true

steps:
- name: Checkout sources
Expand Down Expand Up @@ -94,6 +99,10 @@ jobs:
target
key: ${{ runner.os }}-test-${{ steps.tc.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.toml') }}

- name: Set RUSTFLAGS
if: runner.os != 'Windows'
run: echo "RUSTFLAGS=${{ matrix.rustflags || '' }}" >> $GITHUB_ENV

- name: Build all features
if: matrix.features == ''
run: cargo build --features full-doc
Expand Down
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ optional = true
git = "https://github.com/serenity-rs/serenity"
branch = "next"

[dependencies.simd-json]
optional = true
features = ["serde_impl"]
version = "0.6.0"

[dependencies.streamcatcher]
optional = true
version = "1"
Expand Down Expand Up @@ -227,6 +232,8 @@ zlib-simd = ["twilight-gateway/zlib-simd"]
zlib-stock = ["twilight-gateway/zlib-stock"]
serenity-deps = ["async-trait"]

simdjson = []

rustls-marker = []
native-marker = []

Expand Down
13 changes: 12 additions & 1 deletion Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ args = ["fmt", "--all"]
args = ["build", "--features", "full-doc"]
dependencies = ["format"]

[tasks.build-simd]
args = ["build", "--features", "full-doc,simd-json,serenity/simd_json,twilight-gateway/simd-json"]
command = "cargo"
dependencies = ["format"]
env = { "RUSTFLAGS" = "-C target-cpu=native" }

[tasks.build-examples]
args = ["build", "--manifest-path", "./examples/Cargo.toml", "--workspace"]
command = "cargo"
Expand All @@ -24,7 +30,7 @@ command = "cargo"
dependencies = ["format"]

[tasks.build-variants]
dependencies = ["build", "build-gateway", "build-driver"]
dependencies = ["build", "build-gateway", "build-driver", "build-simd"]

[tasks.check]
args = ["check", "--features", "full-doc"]
Expand All @@ -37,6 +43,11 @@ dependencies = ["format"]
[tasks.test]
args = ["test", "--features", "full-doc"]

[tasks.test-simd]
args = ["test", "--features", "full-doc,simd-json,serenity/simd_json,twilight-gateway/simd-json"]
command = "cargo"
env = { "RUSTFLAGS" = "-C target-cpu=native" }

[tasks.bench]
description = "Runs performance benchmarks."
category = "Test"
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ The library offers:
* And, by default, a fully featured voice system featuring events, queues, RT(C)P packet
handling, seeking on compatible streams, shared multithreaded audio stream caches,
and direct Opus data passthrough from DCA files.
* To be able to use `simd-json` from serenity, you will need to enable the `simdjson`
feature on both songbird and serenity.

## Intents
Songbird's gateway functionality requires you to specify the `GUILD_VOICE_STATES` intent.
Expand Down
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

#[cfg(feature = "serenity")]
use futures::channel::mpsc::TrySendError;
#[cfg(not(feature = "simd-json"))]
pub use serde_json::Error as JsonError;
#[cfg(feature = "serenity")]
use serenity::gateway::InterMessage;
#[cfg(feature = "simd-json")]
pub use simd_json::Error as JsonError;
#[cfg(feature = "gateway")]
use std::{error::Error, fmt};
#[cfg(feature = "twilight")]
Expand Down
2 changes: 1 addition & 1 deletion src/input/adapters/cached/compressed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ impl Compressed {
)?;
let mut metabytes = b"DCA1\0\0\0\0".to_vec();
let orig_len = metabytes.len();
serde_json::to_writer(&mut metabytes, &metadata)?;
crate::json::to_writer(&mut metabytes, &metadata)?;
let meta_len = (metabytes.len() - orig_len)
.try_into()
.map_err(|_| CodecCacheError::MetadataTooLarge)?;
Expand Down
3 changes: 1 addition & 2 deletions src/input/adapters/cached/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::input::AudioStreamError;
use crate::{error::JsonError, input::AudioStreamError};
use audiopus::error::Error as OpusError;
use serde_json::Error as JsonError;
use std::{
error::Error as StdError,
fmt::{Display, Formatter, Result as FmtResult},
Expand Down
6 changes: 4 additions & 2 deletions src/input/codecs/dca/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,11 @@ impl FormatReader for DcaReader {
return symph_err::decode_error("missing DCA1 metadata block");
}

let raw_json = source.read_boxed_slice_exact(size as usize)?;
let mut raw_json = source.read_boxed_slice_exact(size as usize)?;

let metadata: DcaMetadata = serde_json::from_slice::<DcaMetadata>(&raw_json)
// NOTE: must be mut for simd-json.
#[allow(clippy::unnecessary_mut_passed)]
let metadata: DcaMetadata = crate::json::from_slice::<DcaMetadata>(&mut raw_json)
.map_err(|_| SymphError::DecodeError("malformed DCA1 metadata block"))?;

let mut revision = MetadataBuilder::new();
Expand Down
5 changes: 3 additions & 2 deletions src/input/metadata/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::error::JsonError;
use std::time::Duration;
use symphonia_core::{meta::Metadata as ContainerMetadata, probe::ProbedMetadata};

Expand Down Expand Up @@ -47,8 +48,8 @@ pub struct AuxMetadata {

impl AuxMetadata {
/// Extract metadata and details from the output of `ffprobe -of json`.
pub fn from_ffprobe_json(value: &[u8]) -> Result<Self, serde_json::Error> {
let output: ffprobe::Output = serde_json::from_slice(value)?;
pub fn from_ffprobe_json(value: &mut [u8]) -> Result<Self, JsonError> {
let output: ffprobe::Output = crate::json::from_slice(value)?;

Ok(output.into_aux_metadata())
}
Expand Down
4 changes: 2 additions & 2 deletions src/input/sources/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ impl<P: AsRef<Path> + Send + Sync> Compose for File<P> {
"-i",
];

let output = Command::new("ffprobe")
let mut output = Command::new("ffprobe")
.args(&args)
.output()
.await
.map_err(|e| AudioStreamError::Fail(Box::new(e)))?;

AuxMetadata::from_ffprobe_json(&output.stdout[..])
AuxMetadata::from_ffprobe_json(&mut output.stdout[..])
.map_err(|e| AudioStreamError::Fail(Box::new(e)))
}
}
6 changes: 4 additions & 2 deletions src/input/sources/ytdl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,15 @@ impl YoutubeDl {
async fn query(&mut self) -> Result<Output, AudioStreamError> {
let ytdl_args = ["-j", &self.url, "-f", "ba[abr>0][vcodec=none]/best"];

let output = Command::new(self.program)
let mut output = Command::new(self.program)
.args(&ytdl_args)
.output()
.await
.map_err(|e| AudioStreamError::Fail(Box::new(e)))?;

let stdout: Output = serde_json::from_slice(&output.stdout[..])
// NOTE: must be mut for simd-json.
#[allow(clippy::unnecessary_mut_passed)]
let stdout: Output = crate::json::from_slice(&mut output.stdout[..])
.map_err(|e| AudioStreamError::Fail(Box::new(e)))?;

self.metadata = Some(stdout.as_aux_metadata());
Expand Down
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ pub use serenity_voice_model as model;
#[cfg(feature = "driver")]
pub use typemap_rev as typemap;

// Re-export serde-json APIs locally to minimise conditional config elsewhere.
#[cfg(not(feature = "simd-json"))]
pub(crate) use serde_json as json;
#[cfg(feature = "simd-json")]
pub(crate) use simd_json::serde as json;

#[cfg(feature = "driver")]
pub use crate::{
driver::Driver,
Expand Down
10 changes: 5 additions & 5 deletions src/ws.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::model::Event;
use crate::{error::JsonError, model::Event};

use async_trait::async_trait;
use async_tungstenite::{
Expand All @@ -8,7 +8,6 @@ use async_tungstenite::{
WebSocketStream,
};
use futures::{SinkExt, StreamExt, TryStreamExt};
use serde_json::Error as JsonError;
use tokio::time::{timeout, Duration};
use tracing::instrument;

Expand Down Expand Up @@ -92,7 +91,7 @@ impl ReceiverExt for WsStream {
#[async_trait]
impl SenderExt for SplitSink<WsStream, Message> {
async fn send_json(&mut self, value: &Event) -> Result<()> {
Ok(serde_json::to_string(value)
Ok(crate::json::to_string(value)
.map(Message::Text)
.map_err(Error::from)
.map(|m| self.send(m))?
Expand All @@ -103,7 +102,7 @@ impl SenderExt for SplitSink<WsStream, Message> {
#[async_trait]
impl SenderExt for WsStream {
async fn send_json(&mut self, value: &Event) -> Result<()> {
Ok(serde_json::to_string(value)
Ok(crate::json::to_string(value)
.map(Message::Text)
.map_err(Error::from)
.map(|m| self.send(m))?
Expand All @@ -114,7 +113,8 @@ impl SenderExt for WsStream {
#[inline]
pub(crate) fn convert_ws_message(message: Option<Message>) -> Result<Option<Event>> {
Ok(match message {
Some(Message::Text(payload)) => serde_json::from_str(&payload).map(Some)?,
Some(Message::Text(mut payload)) =>
crate::json::from_str(payload.as_mut_str()).map(Some)?,
Some(Message::Binary(bytes)) => {
return Err(Error::UnexpectedBinaryMessage(bytes));
},
Expand Down