Skip to content

Commit

Permalink
Add rspc-core crate + drop unstablemodule
Browse files Browse the repository at this point in the history
  • Loading branch information
oscartbeaumont committed Oct 9, 2023
1 parent 59bb9f0 commit 6d7bf81
Show file tree
Hide file tree
Showing 53 changed files with 711 additions and 729 deletions.
15 changes: 8 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ harness = false

[features]
default = ["typescript"]
typescript = ["specta/typescript"]
tracing = ["dep:tracing"]
tokio = ["dep:tokio", "specta/tokio"]
typescript = ["rspc-core/typescript", "specta/typescript"]
tracing = ["rspc-core/tracing", "dep:tracing"]
tokio = ["rspc-core/tokio", "dep:tokio", "specta/tokio"]

unstable = [] # APIs where one line of code can blow up your whole app

[dependencies]
rspc-core = { path = "./crates/core" }

specta = { workspace = true }
serde = { workspace = true }
thiserror = { workspace = true }
Expand All @@ -48,10 +50,9 @@ serde_json = { version = "1", default-features = false }
tracing = { version = "0.1.37", default-features = false, optional = true }
tokio = { version = "1", default-features = false, features = ["rt", "time"], optional = true }

# TODO: Does this negatively affect compile times? Should it be flipped?
# # Even though this `cfg` can never be enabled, it still forces cargo to keep `serde_derive` in lockstep with `serde`.
# [target.'cfg(any())'.dependencies]
# rspc_httpz = { version = "=1.0.185", path = "../serde_derive" }
# Even though this `cfg` can never be enabled, it still forces cargo to keep `rspc-core` in lockstep with `rspc`.
[target.'cfg(any())'.dependencies]
rspc-core = { version = "=1.0.0-rc.5", path = "./crates/core" }

[dev-dependencies]
# Tests
Expand Down
24 changes: 24 additions & 0 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,28 @@ name = "rspc-core"
version = "1.0.0-rc.5"
edition = "2021"

# TODO: Remove all features from this crate cause they mean we can optimise build time
[features]
default = []
typescript = ["specta/typescript"]
tracing = ["dep:tracing"]
tokio = ["dep:tokio", "specta/tokio"]

[dependencies]
specta = { workspace = true, features = ["typescript"] } # TODO: `typescript` should be required
serde = { workspace = true }
thiserror = { workspace = true }
futures = { version = "0.3.28", default-features = false, features = ["std", "async-await"] } # TODO: Drop for `futures_core` if possible
pin-project-lite = "0.2.13"
serde_json = { version = "1", default-features = false }
streamunordered = "0.5.3"

# TODO: Remove these from core
tracing = { version = "0.1.37", default-features = false, optional = true }
tokio = { version = "1", default-features = false, features = ["rt", "time"], optional = true }

# TODO: Make something like this work
# # Even though this `cfg` can never be enabled, it still forces cargo to keep `rspc-core` in lockstep with `rspc-*`.
# [target.'cfg(any())'.dependencies]
# rspc-httpz = { version = "=1.0.0-rc.5", path = "../httpz" }
# rspc-tauri = { version = "=1.0.0-rc.5", path = "../tauri" }
File renamed without changes.
2 changes: 1 addition & 1 deletion src/internal/body/body.rs → crates/core/src/body/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{

use serde_json::Value;

use crate::ExecError;
use crate::error::ExecError;

/// The resulting body from an rspc operation.
///
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions src/internal/body/mod.rs → crates/core/src/body/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ mod map;
mod once;

pub use body::*;
pub use map::*;
pub use once::*;
pub(crate) use map::*;
pub(crate) use once::*;
2 changes: 1 addition & 1 deletion src/internal/body/once.rs → crates/core/src/body/once.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use futures::ready;
use pin_project_lite::pin_project;
use serde_json::Value;

use crate::ExecError;
use crate::error::ExecError;

use super::Body;

Expand Down
43 changes: 18 additions & 25 deletions src/error.rs → crates/core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,28 @@ pub enum ProcedureError {
Resolver(serde_json::Value),
}

mod private {
use super::*;

pub trait IntoResolverError: Serialize + Type + std::error::Error {
fn into_resolver_error(self) -> ResolverError
where
Self: Sized,
{
ResolverError {
value: serde_json::to_value(&self).unwrap_or_default(),
message: self.to_string(),
}
pub trait IntoResolverError: Serialize + Type + std::error::Error {
fn into_resolver_error(self) -> ResolverError
where
Self: Sized,
{
ResolverError {
value: serde_json::to_value(&self).unwrap_or_default(),
message: self.to_string(),
}
}
}

#[derive(thiserror::Error, Debug, Clone)]
#[error("{message}")]
pub struct ResolverError {
pub(crate) value: serde_json::Value,
pub(crate) message: String,
}
#[derive(thiserror::Error, Debug, Clone)]
#[error("{message}")]
pub struct ResolverError {
pub(crate) value: serde_json::Value,
pub(crate) message: String,
}

impl From<ResolverError> for ProcedureError {
fn from(v: ResolverError) -> Self {
Self::Resolver(v.value)
}
impl From<ResolverError> for ProcedureError {
fn from(v: ResolverError) -> Self {
Self::Resolver(v.value)
}
}

Expand All @@ -43,9 +39,6 @@ pub enum Infallible {}

impl<T> IntoResolverError for T where T: Serialize + Type + std::error::Error {}

// TODO: `ResolverError` should probs be public from rspc-core but not rspc
pub(crate) use private::{IntoResolverError, ResolverError};

// TODO: Context based `ExecError`. Always include the `path` of the procedure on it.
// TODO: Cleanup this
#[derive(thiserror::Error, Debug)]
Expand Down
13 changes: 6 additions & 7 deletions src/internal/exec/arc_ref.rs → crates/core/src/exec/arc_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@ use std::{
use serde_json::Value;

use crate::{
internal::{
middleware::{ProcedureKind, RequestContext},
procedure::ProcedureTodo,
Body,
},
ProcedureMap, Router,
body::Body,
middleware::{ProcedureKind, RequestContext},
procedure_store::ProcedureTodo,
router_builder::ProcedureMap,
Router,
};

use super::{ExecutorResult, RequestData};
use super::RequestData;

pub(crate) struct ArcRef<T: 'static> {
// The lifetime here is invalid. This type is actually valid as long as the `Arc` in `self.mem` is ok.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,11 @@ use pin_project_lite::pin_project;
use serde_json::Value;
use streamunordered::{StreamUnordered, StreamYield};

use super::{AsyncRuntime, ExecutorResult, IncomingMessage, Request, Requests, Response, Task};
use super::{ExecutorResult, IncomingMessage, Request, Requests, Response, Task};
use crate::{
internal::{
exec::{self, ResponseInner},
PinnedOption, PinnedOptionProj,
},
Router,
exec,
util::{PinnedOption, PinnedOptionProj},
AsyncRuntime, Router,
};

// Time to wait for more messages before sending them over the websocket connection.
Expand Down
21 changes: 11 additions & 10 deletions src/internal/exec/execute.rs → crates/core/src/exec/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@ use futures::{channel::oneshot, stream::FuturesUnordered, Stream, StreamExt};
use serde_json::Value;

use crate::{
internal::{
exec::{
arc_ref::{self, get_subscription, ArcRef},
request_future::RequestFuture,
Request, Response, ResponseInner, Task,
},
middleware::{ProcedureKind, RequestContext},
procedure::ProcedureTodo,
Body, FutureValueOrStream,
body::Body,
error::ExecError,
exec::{
arc_ref::{self, get_subscription, ArcRef},
request_future::RequestFuture,
Request, Response, ResponseInner, Task,
},
ExecError, ProcedureMap, Router,
layer::FutureValueOrStream,
middleware::{ProcedureKind, RequestContext},
procedure_store::ProcedureTodo,
router_builder::ProcedureMap,
Router,
};

use super::{task, Connection, RequestData};
Expand Down
4 changes: 0 additions & 4 deletions src/internal/exec/mod.rs → crates/core/src/exec/mod.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
//! TODO: Module docs

#![allow(unused_imports)]

pub(crate) mod arc_ref;
mod async_runtime;
mod connection;
mod execute;
mod request_future;
mod sink_and_stream;
mod task;
mod types;

pub use async_runtime::*;
pub use connection::*;
#[allow(unused_imports)]
pub use execute::*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ use pin_project_lite::pin_project;
use serde_json::Value;

use crate::{
internal::{
exec::{self, Response, ResponseInner},
middleware::RequestContext,
Body, PinnedOption, PinnedOptionProj,
},
ExecError, Router,
body::Body,
error::ExecError,
exec::{self, Response, ResponseInner},
middleware::RequestContext,
util::{PinnedOption, PinnedOptionProj},
Router,
};

use super::arc_ref::ArcRef;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::{

use futures::{Sink, Stream};

// TODO: Surely the `futures` crate has something that can replace this?
pin_project_lite::pin_project! {
pub struct SinkAndStream<TSink, TStream> {
#[pin]
Expand Down
15 changes: 4 additions & 11 deletions src/internal/exec/task.rs → crates/core/src/exec/task.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use std::{fmt, pin::Pin, sync::Arc, task::Poll};
use std::{fmt, pin::Pin, task::Poll};

use futures::{ready, Stream};

use crate::{
internal::{exec, Body},
Router,
};
use crate::body::Body;
use crate::exec;

use super::{arc_ref::ArcRef, request_future::RequestFuture};

// TODO: Should this be called `Task` or `StreamWrapper`? Will depend on it's final form.

// TODO: Replace with FusedStream in dev if possible???
pub enum Status {
ShouldBePolled { done: bool },
DoNotPoll,
Expand All @@ -22,16 +21,10 @@ pub struct Task {
// You will notice this is a `Stream` not a `Future` like would be implied by the struct.
// rspc's whole middleware system only uses `Stream`'s cause it makes life easier so we change to & from a `Future` at the start/end.
pub(crate) stream: ArcRef<Pin<Box<dyn Body + Send>>>,
// pub(crate) shutdown
// Mark when the stream is done. This means `self.reference` returned `None` but we still had to yield the complete message so we haven't returned `None` yet.
pub(crate) status: Status,
}

// pub enum Inner {
// Task(Task),
// Response(exec::Response),
// }

impl fmt::Debug for Task {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StreamWrapper")
Expand Down
73 changes: 73 additions & 0 deletions crates/core/src/exec/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use std::borrow::Cow;

use serde::{Deserialize, Serialize};
use serde_json::Value;
use specta::Type;

use crate::error::ProcedureError;

#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Type)]
pub struct RequestData {
/// A unique ID used to identify the request
/// It is the client's responsibility to ensure that this ID is unique.
/// When using the HTTP Link this will always be `0`.
pub id: u32,
pub path: Cow<'static, str>,
pub input: Option<Value>,
}

/// The type of a request to rspc.
///
/// @internal
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Type)]
#[serde(tag = "method", rename_all = "camelCase")]
pub enum Request {
Query(RequestData),
Mutation(RequestData),
Subscription(RequestData),
SubscriptionStop { id: u32 },
}

/// A value that can be a successful result or an error.
///
/// @internal
#[derive(Clone, Debug, Serialize, PartialEq, Eq, Type)]
// #[cfg_attr(test, derive(specta::Type))]
#[serde(tag = "type", content = "value", rename_all = "camelCase")]
pub enum ResponseInner {
/// The result of a successful operation.
Value(Value),
/// The result of a failed operation.
Error(ProcedureError),
/// A message to indicate that the operation is complete.
Complete,
}

/// The type of a response from rspc.
///
/// @internal
#[derive(Clone, Debug, Serialize, PartialEq, Eq, Type)]
// #[cfg_attr(test, derive(specta::Type))]
#[serde(rename_all = "camelCase")]
pub struct Response {
pub id: u32,
#[serde(flatten)]
pub inner: ResponseInner,
}

#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Type)]
pub enum Requests {
One(Request),
Many(Vec<Request>),
}

/// The type of an incoming message to the [`Connection`] abstraction.
///
/// This allows it to be used with any socket that can convert into this type.
#[derive(Debug)]
#[allow(dead_code)]
pub enum IncomingMessage {
Msg(Result<serde_json::Value, serde_json::Error>),
Close,
Skip,
}
3 changes: 0 additions & 3 deletions crates/core/src/internal/mod.rs

This file was deleted.

Loading

0 comments on commit 6d7bf81

Please sign in to comment.