Skip to content

Commit

Permalink
Gate async functionality behind a feature (#278)
Browse files Browse the repository at this point in the history
Add async (for async overall) and async-adapter (for the ability to use naturally-sync backends like sqlite from async) features
  • Loading branch information
Electron100 authored Nov 18, 2024
1 parent b325162 commit e50b891
Show file tree
Hide file tree
Showing 24 changed files with 155 additions and 75 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ build :
cd butane && $(CARGO) check --features pg
cd butane && $(CARGO) check --features pg,datetime
cd butane && $(CARGO) check --features sqlite
cd examples/getting_started && $(CARGO) check --features "sqlite,sqlite-bundled"
cargo build --all-features

lint :
Expand All @@ -21,6 +22,8 @@ check : build doclint lint spellcheck check-fmt test

test :
$(CARGO) test --all-features
# And run the example tests separately to avoid feature combinations
cd examples; for dir in *; do cargo +stable test -p $dir --all-features; done

clean :
$(CARGO) clean
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ Butane exposes several features to Cargo. By default, no backends are
enabled: you will want to enable `sqlite` and/or `pg`:

* `default`: Turns on `datetime`, `json` and `uuid`.
* `async`: Turns on async support. This is automatically enabled for the `pg` backend, which is implemented on the `tokio-postgres` crate.
* `async-adapter`: Enables the use of `async` with the `sqlite` backend, which is not natively async.
* `debug`: Used in developing Butane, not expected to be enabled by consumers.
* `datetime`: Support for timestamps (using [`chrono`](https://crates.io/crates/chrono) crate).
* `fake`: Support for the [`fake`](https://crates.io/crates/fake) crate's generation of fake data.
Expand Down
2 changes: 1 addition & 1 deletion async_checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
* [x] Fully support sync too. Using async should not be required
* [ ] Clean up miscellaneous TODOs
* [x] Establish soundness for unsafe sections of AsyncAdapter
* [ ] Should async and/or async_adapter be under a separate feature?
* [x] Should async and/or async_adapter be under a separate feature?
* [ ] Integrate deadpool or bb8 for async connection pool
5 changes: 3 additions & 2 deletions butane/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ documentation = "https://docs.rs/butane/"
build = "build.rs"

[features]
async = ["butane_core/async", "butane_codegen/async"]
async-adapter = ["butane_core/async-adapter"]
default = ["datetime", "json", "uuid"]
fake = ["butane_core/fake"]
json = ["butane_codegen/json", "butane_core/json"]
sqlite = ["butane_core/sqlite"]
sqlite-bundled = ["butane_core/sqlite-bundled"]
pg = ["butane_core/pg"]
pg = ["async", "butane_core/pg"]
datetime = ["butane_codegen/datetime", "butane_core/datetime"]
debug = ["butane_core/debug"]
log = ["butane_core/log"]
Expand All @@ -27,7 +29,6 @@ tls = ["butane_core/tls"]
uuid = ["butane_codegen/uuid", "butane_core/uuid"]

[dependencies]
async-trait = { workspace = true }
butane_codegen = { workspace = true }
butane_core = { workspace = true }

Expand Down
11 changes: 6 additions & 5 deletions butane/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
pub use butane_codegen::{butane_type, dataresult, model, FieldType, PrimaryKeyType};
pub use butane_core::custom;
pub use butane_core::fkey::ForeignKey;
pub use butane_core::many::{Many, ManyOpsAsync, ManyOpsSync};
pub use butane_core::many::{Many, ManyOpsSync};
pub use butane_core::migrations;
pub use butane_core::query;
#[cfg(feature = "async")]
pub use butane_core::{many::ManyOpsAsync, DataObjectOpsAsync};
pub use butane_core::{
AsPrimaryKey, AutoPk, DataObject, DataObjectOpsAsync, DataObjectOpsSync, DataResult, Error,
FieldType, FromSql, PrimaryKeyType, Result, SqlType, SqlVal, SqlValRef, ToSql,
AsPrimaryKey, AutoPk, DataObject, DataObjectOpsSync, DataResult, Error, FieldType, FromSql,
PrimaryKeyType, Result, SqlType, SqlVal, SqlValRef, ToSql,
};

pub mod db {
Expand Down Expand Up @@ -196,6 +198,7 @@ pub mod prelude {
pub use butane_core::DataObjectOpsSync;
}

#[cfg(feature = "async")]
pub mod prelude_async {
//! Prelude module to improve ergonomics in async operation. Brings certain traits into scope.
//!
Expand All @@ -214,7 +217,5 @@ pub mod internal {
//!
//! Do not use directly. Semver-exempt.
pub use async_trait::async_trait;

pub use butane_core::internal::*;
}
1 change: 1 addition & 0 deletions butane_codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ license.workspace = true
repository.workspace = true

[features]
async = ["butane_core/async"]
datetime = ["butane_core/datetime"]
json = ["butane_core/json"]
uuid = ["butane_core/uuid"]
Expand Down
12 changes: 6 additions & 6 deletions butane_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ repository.workspace = true


[features]
async-adapter = []
async-adapter = ["async", "crossbeam-channel"]
async = ["tokio"]
datetime = ["chrono", "tokio-postgres?/with-chrono-0_4"]
debug = ["log"]
fake = ["dep:fake", "rand"]
json = ["tokio-postgres?/with-serde_json-1", "rusqlite?/serde_json"]
log = ["dep:log", "rusqlite?/trace"]
pg = ["bytes", "tokio-postgres"]
sqlite = ["rusqlite", "async-adapter"]
pg = ["async", "bytes", "tokio-postgres"]
sqlite = ["rusqlite"]
sqlite-bundled = ["rusqlite/bundled"]
tls = ["native-tls", "postgres-native-tls"]

Expand All @@ -27,8 +28,7 @@ async-trait = { workspace = true}
bytes = { version = "1.0", optional = true }
cfg-if = { workspace = true }
chrono = { optional = true, workspace = true }
# todo make adapter optional
crossbeam-channel = { workspace = true }
crossbeam-channel = { workspace = true, optional = true}
dyn-clone = { version = "1.0" }
fake = { workspace = true, optional = true }
fallible-iterator = "0.3"
Expand All @@ -42,7 +42,7 @@ native-tls = { version = "0.2", optional = true }
nonempty.workspace = true
once_cell = { workspace = true }
pin-project = "1"
tokio = {workspace = true, features = ["rt", "sync", "rt-multi-thread"]}
tokio = {workspace = true, optional = true, features = ["rt", "sync", "rt-multi-thread"]}
tokio-postgres = { optional = true, workspace = true }
postgres-native-tls = { version = "0.5", optional = true }
proc-macro2 = { workspace = true }
Expand Down
35 changes: 27 additions & 8 deletions butane_core/src/codegen/dbobj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ pub fn impl_dbobject(ast_struct: &ItemStruct, config: &Config) -> TokenStream2 {
let values_no_pk: Vec<TokenStream2> = push_values(ast_struct, |f: &Field| f != &pk_field);
let insert_cols = columns(ast_struct, |f| !is_auto(f));

let many_save_async = impl_many_save(ast_struct, config, true);
let many_save_sync = impl_many_save(ast_struct, config, false);
let save_many_to_many_async = def_for_save_many_to_many_async(ast_struct, config);

let conn_arg_name = if many_save_sync.is_empty() {
syn::Ident::new("_conn", Span::call_site())
Expand Down Expand Up @@ -83,13 +83,7 @@ pub fn impl_dbobject(ast_struct: &ItemStruct, config: &Config) -> TokenStream2 {
fn pk_mut(&mut self) -> &mut impl butane::PrimaryKeyType {
&mut self.#pkident
}
async fn save_many_to_many_async(
&mut self,
#conn_arg_name: &impl butane::db::ConnectionMethodsAsync,
) -> butane::Result<()> {
#many_save_async
Ok(())
}
#save_many_to_many_async
fn save_many_to_many_sync(
&mut self,
#conn_arg_name: &impl butane::db::ConnectionMethods,
Expand Down Expand Up @@ -459,3 +453,28 @@ fn impl_many_save(ast_struct: &ItemStruct, config: &Config, is_async: bool) -> T
})
.collect();
}

#[cfg(feature = "async")]
fn def_for_save_many_to_many_async(ast_struct: &ItemStruct, config: &Config) -> TokenStream2 {
let many_save_async = impl_many_save(ast_struct, config, true);
let conn_arg_name = if many_save_async.is_empty() {
syn::Ident::new("_conn", Span::call_site())
} else {
syn::Ident::new("conn", Span::call_site())
};

quote!(
async fn save_many_to_many_async(
&mut self,
#conn_arg_name: &impl butane::db::ConnectionMethodsAsync,
) -> butane::Result<()> {
#many_save_async
Ok(())
}
)
}

#[cfg(not(feature = "async"))]
fn def_for_save_many_to_many_async(_ast_struct: &ItemStruct, _config: &Config) -> TokenStream2 {
quote!()
}
7 changes: 6 additions & 1 deletion butane_core/src/db/connmethods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{Result, SqlType, SqlVal, SqlValRef};
/// implemented by both database connections and transactions.
#[maybe_async_cfg::maybe(
sync(keep_self),
async(self = "ConnectionMethodsAsync"),
async(feature = "async", self = "ConnectionMethodsAsync"),
idents(AsyncRequiresSync)
)]
#[async_trait]
Expand Down Expand Up @@ -156,6 +156,7 @@ impl<T> VecRows<T> {
}
}

#[cfg(feature = "async-adapter")]
pub(crate) fn vec_from_backend_rows<'a>(
mut other: Box<dyn BackendRows + 'a>,
columns: &[Column],
Expand Down Expand Up @@ -191,11 +192,13 @@ impl<'a> BackendRows for Box<dyn BackendRows + 'a> {
}
}

#[cfg(feature = "async-adapter")]
#[derive(Debug)]
pub(crate) struct VecRow {
values: Vec<SqlVal>,
}

#[cfg(feature = "async-adapter")]
impl VecRow {
fn new(original: &(dyn BackendRow), columns: &[Column]) -> Result<Self> {
if original.len() != columns.len() {
Expand All @@ -214,6 +217,8 @@ impl VecRow {
})
}
}

#[cfg(feature = "async-adapter")]
impl BackendRow for VecRow {
fn get(&self, idx: usize, ty: SqlType) -> Result<SqlValRef> {
self.values
Expand Down
2 changes: 1 addition & 1 deletion butane_core/src/db/dummy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl ConnectionMethods for DummyConnection {
),
keep_self,
sync(),
async()
async(feature = "async")
)]
#[async_trait]
impl BackendConnection for DummyConnection {
Expand Down
2 changes: 1 addition & 1 deletion butane_core/src/db/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ macro_rules! connection_method_wrapper {
Transaction(sync = "Transaction")
),
sync(keep_self),
async()
async(feature = "async")
)]
#[async_trait::async_trait]
impl ConnectionMethods for $ty {
Expand Down
Loading

0 comments on commit e50b891

Please sign in to comment.