Skip to main content

SecureConn

Struct SecureConn 

Source
pub struct SecureConn { /* private fields */ }
Expand description

Secure database connection wrapper.

This is the primary interface for module developers to access the database. All operations require a SecurityCtx parameter for per-request access control.

§Usage

Module services receive a &SecureConn and provide SecurityCtx per-request:

pub struct MyService<'a> {
    db: &'a SecureConn,
}

impl<'a> MyService<'a> {
    pub async fn get_user(&self, scope: &AccessScope, id: Uuid) -> Result<Option<User>> {
        self.db.find_by_id::<user::Entity>(ctx, id)?
            .one(self.db.conn())
            .await
    }
}

§Security Guarantees

  • All queries require SecurityCtx from the request
  • Queries are scoped by tenant/resource from the context
  • Empty scopes result in deny-all (no data returned)
  • Type system prevents unscoped queries from compiling
  • Cannot bypass security without insecure-escape feature

Implementations§

Source§

impl SecureConn

Source

pub fn new(conn: DatabaseConnection) -> Self

Create a new secure database connection wrapper.

Typically created via DbHandle::sea_secure() rather than directly.

Source

pub fn conn(&self) -> &DatabaseConnection

Get a reference to the underlying database connection.

§Safety

Use with caution. Direct connection access bypasses automatic scoping. Prefer the high-level methods (find, update_many, etc.) whenever possible.

Valid use cases:

  • Executing already-scoped queries (.one(), .all(), .exec())
  • Complex joins that need custom SeaORM building
  • Internal infrastructure code (not module business logic)
Source

pub fn db_engine(&self) -> &'static str

Return database engine identifier for tracing / logging.

Source

pub fn find<E>(&self, scope: &AccessScope) -> SecureSelect<E, Scoped>

Create a scoped select query for the given entity.

Returns a SecureSelect<E, Scoped> that automatically applies tenant/resource filtering based on the provided security context.

§Example
let ctx = SecurityCtx::for_tenants(vec![tenant_id], user_id);
let users = db.find::<user::Entity>(&ctx)?
    .filter(user::Column::Status.eq("active"))
    .order_by_asc(user::Column::Email)
    .all(db.conn())
    .await?;
§Errors
Source

pub fn find_by_id<E>( &self, scope: &AccessScope, id: Uuid, ) -> Result<SecureSelect<E, Scoped>, ScopeError>

Create a scoped select query filtered by a specific resource ID.

This is a convenience method that combines find() with .and_id().

§Example
let ctx = SecurityCtx::for_tenants(vec![tenant_id], user_id);
let user = db.find_by_id::<user::Entity>(&ctx, user_id)?
    .one(db.conn())
    .await?;
§Errors

Returns ScopeError if the entity doesn’t have a resource column or scoping fails.

Source

pub fn update_many<E>(&self, scope: &AccessScope) -> SecureUpdateMany<E, Scoped>

Create a scoped update query for the given entity.

Returns a SecureUpdateMany<E, Scoped> that automatically applies tenant/resource filtering. Use .col_expr() or other SeaORM methods to specify what to update.

§Example
let ctx = SecurityCtx::for_tenants(vec![tenant_id], user_id);
let result = db.update_many::<user::Entity>(&ctx)?
    .col_expr(user::Column::Status, Expr::value("active"))
    .col_expr(user::Column::UpdatedAt, Expr::value(Utc::now()))
    .exec(db.conn())
    .await?;
println!("Updated {} rows", result.rows_affected);
Source

pub fn delete_many<E>(&self, scope: &AccessScope) -> SecureDeleteMany<E, Scoped>

Create a scoped delete query for the given entity.

Returns a SecureDeleteMany<E, Scoped> that automatically applies tenant/resource filtering.

§Example
let ctx = SecurityCtx::for_tenants(vec![tenant_id], user_id);
let result = db.delete_many::<user::Entity>(&ctx)?
    .exec(db.conn())
    .await?;
println!("Deleted {} rows", result.rows_affected);
Source

pub async fn insert<E>( &self, scope: &AccessScope, am: E::ActiveModel, ) -> Result<E::Model, ScopeError>

Insert a new entity with automatic tenant validation.

This is a convenience wrapper around secure_insert() that uses the provided security context.

§Example
let ctx = SecurityCtx::for_tenants(vec![tenant_id], user_id);
let am = user::ActiveModel {
    id: Set(Uuid::new_v4()),
    tenant_id: Set(tenant_id),
    owner_id: Set(ctx.subject_id),
    email: Set("user@example.com".to_string()),
    ..Default::default()
};

let user = db.insert::<user::Entity>(&ctx, am).await?;
§Errors
  • ScopeError::Invalid if entity requires tenant but scope has none
  • ScopeError::Db if database insert fails
Source

pub async fn update_one<E>( &self, am: E::ActiveModel, ) -> Result<E::Model, ScopeError>

Update a single entity by ID (unscoped).

Warning: This method does NOT validate security scope. Use update_with_ctx() for scope-validated updates.

This is a convenience method for the common pattern of updating one record when you’ve already validated access separately.

§Example
let mut user: user::ActiveModel = db.find_by_id::<user::Entity>(id)?
    .one(db.conn())
    .await?
    .ok_or(NotFound)?
    .into();

user.email = Set("newemail@example.com".to_string());
user.updated_at = Set(Utc::now());

let updated = db.update_one(user).await?;
§Errors

Returns ScopeError::Db if the database update fails.

Source

pub async fn update_with_ctx<E>( &self, scope: &AccessScope, id: Uuid, am: E::ActiveModel, ) -> Result<E::Model, ScopeError>

Update a single entity with security scope validation.

This method ensures the entity being updated is within the security scope before performing the update. It validates that the record is accessible based on tenant/resource constraints.

§Security
  • Validates the entity exists and is accessible in the security scope
  • Returns ScopeError::Denied if the entity is not in scope
  • Ensures updates cannot affect entities outside the security boundary
§Example
let ctx = SecurityCtx::for_tenant(tenant_id, user_id);

// Load and modify
let user_model = db.find_by_id::<user::Entity>(&ctx, id)?
    .one(db.conn())
    .await?
    .ok_or(NotFound)?;

let mut user: user::ActiveModel = user_model.into();
user.email = Set("newemail@example.com".to_string());
user.updated_at = Set(Utc::now());

// Update with scope validation (pass ID separately)
let updated = db.update_with_ctx::<user::Entity>(&ctx, id, user).await?;
§Errors
  • ScopeError::Denied if the entity is not accessible in the current scope
  • ScopeError::Db if the database operation fails
Source

pub async fn delete_by_id<E>( &self, scope: &AccessScope, id: Uuid, ) -> Result<bool, ScopeError>

Delete a single entity by ID (scoped).

This validates the entity exists in scope before deleting.

§Example
let ctx = SecurityCtx::for_tenants(vec![tenant_id], user_id);
db.delete_by_id::<user::Entity>(&ctx, user_id).await?;
§Returns
  • Ok(true) if entity was deleted
  • Ok(false) if entity not found in scope
§Errors

Returns ScopeError::Invalid if the entity does not have a resource_col defined.

Source

pub async fn transaction<T, F>(&self, f: F) -> Result<T>
where T: Send + 'static, F: for<'c> FnOnce(&'c DatabaseTransaction) -> Pin<Box<dyn Future<Output = Result<T>> + Send + 'c>> + Send,

Execute a closure inside a database transaction.

This method starts a SeaORM transaction, provides the transaction handle to the closure as &dyn ConnectionTrait, and handles commit/rollback.

§Return Type

Returns anyhow::Result<Result<T, E>> where:

  • Outer Err: Database/infrastructure error (transaction rolls back)
  • Inner Ok(T): Success (transaction commits)
  • Inner Err(E): Domain/validation error (transaction still commits)

This design ensures domain validation errors don’t cause rollback.

§Architecture Note

Transaction boundaries should be managed by application/domain services, not by REST handlers. REST handlers should call service methods that internally decide when to open transactions.

§Example
use modkit_db::secure::SecureConn;

// In a domain service:
pub async fn create_user(
    db: &SecureConn,
    repo: &UsersRepo,
    user: User,
) -> Result<User, DomainError> {
    let result = db.transaction(|conn| async move {
        // Check email uniqueness
        if repo.email_exists(conn, &user.email).await? {
            return Ok(Err(DomainError::EmailExists));
        }
        // Create user
        let created = repo.create(conn, user).await?;
        Ok(Ok(created))
    }).await?;
    result
}
§Errors

Returns Err(anyhow::Error) if:

  • The transaction cannot be started
  • A database operation fails (transaction is rolled back)
  • The commit fails
Source

pub async fn transaction_with_config<T, F>( &self, cfg: TxConfig, f: F, ) -> Result<T>
where T: Send + 'static, F: for<'c> FnOnce(&'c DatabaseTransaction) -> Pin<Box<dyn Future<Output = Result<T>> + Send + 'c>> + Send,

Execute a closure inside a database transaction with custom configuration.

This method is similar to transaction, but allows specifying the isolation level and access mode.

§Configuration

Use TxConfig to specify transaction settings without importing SeaORM types:

use modkit_db::secure::{TxConfig, TxIsolationLevel, TxAccessMode};

let cfg = TxConfig {
    isolation: Some(TxIsolationLevel::Serializable),
    access_mode: Some(TxAccessMode::ReadWrite),
};
§Example
use modkit_db::secure::{SecureConn, TxConfig, TxIsolationLevel};

// In a domain service requiring serializable isolation:
pub async fn reconcile_accounts(
    db: &SecureConn,
    repo: &AccountsRepo,
) -> anyhow::Result<Result<ReconciliationResult, DomainError>> {
    let cfg = TxConfig::serializable();

    db.transaction_with_config(cfg, |conn| async move {
        let accounts = repo.find_all_pending(conn).await?;
        for account in accounts {
            repo.reconcile(conn, &account).await?;
        }
        Ok(Ok(ReconciliationResult { processed: accounts.len() }))
    }).await
}
§Backend Notes
  • PostgreSQL: Full support for all isolation levels and access modes.
  • MySQL/InnoDB: Full support for all isolation levels and access modes.
  • SQLite: Only supports Serializable isolation. Other levels are mapped to Serializable. Read-only mode is a hint only.
§Errors

Returns Err(anyhow::Error) if:

  • The transaction cannot be started with the specified configuration
  • A database operation fails (transaction is rolled back)
  • The commit fails
Source

pub async fn in_transaction<T, E, F>(&self, f: F) -> Result<T, TxError<E>>
where T: Send + 'static, E: Debug + Display + Send + 'static, F: for<'c> FnOnce(&'c DatabaseTransaction) -> Pin<Box<dyn Future<Output = Result<T, E>> + Send + 'c>> + Send,

Execute a closure inside a typed domain transaction.

This method returns TxError<E> which distinguishes domain errors from infrastructure errors, allowing callers to handle them appropriately.

§Error Handling
  • Domain errors returned from the closure are wrapped in TxError::Domain(e)
  • Database infrastructure errors are wrapped in TxError::Infra(InfraError)

Use TxError::into_domain to convert the result into your domain error type.

§Example
use modkit_db::secure::SecureConn;

async fn create_user(db: &SecureConn, repo: &UsersRepo, user: User) -> Result<User, DomainError> {
    db.in_transaction(move |tx| Box::pin(async move {
        if repo.exists(tx, user.id).await? {
            return Err(DomainError::already_exists(user.id));
        }
        repo.create(tx, user).await
    }))
    .await
    .map_err(|e| e.into_domain(DomainError::database_infra))
}
§Errors

Returns Err(TxError<E>) if:

  • The callback returns a domain error (TxError::Domain(E)).
  • The transaction fails due to a database/infrastructure error (TxError::Infra(InfraError)).
Source

pub async fn in_transaction_mapped<T, E, F, M>( &self, map_infra: M, f: F, ) -> Result<T, E>
where T: Send + 'static, E: Debug + Display + Send + 'static, M: FnOnce(InfraError) -> E + Send, F: for<'c> FnOnce(&'c DatabaseTransaction) -> Pin<Box<dyn Future<Output = Result<T, E>> + Send + 'c>> + Send,

Execute a typed domain transaction with automatic infrastructure error mapping.

This is a convenience wrapper around in_transaction that automatically converts TxError into the domain error type using the provided mapping function for infrastructure errors.

§Example
use modkit_db::secure::SecureConn;

async fn create_user(db: &SecureConn, repo: &UsersRepo, user: User) -> Result<User, DomainError> {
    db.in_transaction_mapped(DomainError::database_infra, move |tx| Box::pin(async move {
        if repo.exists(tx, user.id).await? {
            return Err(DomainError::already_exists(user.id));
        }
        repo.create(tx, user).await
    })).await
}
§Errors

Returns Err(E) if:

  • The callback returns a domain error (E).
  • The transaction fails due to a database/infrastructure error, mapped via map_infra.

Trait Implementations§

Source§

impl Clone for SecureConn

Source§

fn clone(&self) -> SecureConn

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Paint for T
where T: ?Sized,

Source§

fn fg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the foreground set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like red() and green(), which have the same functionality but are pithier.

§Example

Set foreground color to white using fg():

use yansi::{Paint, Color};

painted.fg(Color::White);

Set foreground color to white using white().

use yansi::Paint;

painted.white();
Source§

fn primary(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Primary].

§Example
println!("{}", value.primary());
Source§

fn fixed(&self, color: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Fixed].

§Example
println!("{}", value.fixed(color));
Source§

fn rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Rgb].

§Example
println!("{}", value.rgb(r, g, b));
Source§

fn black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Black].

§Example
println!("{}", value.black());
Source§

fn red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Red].

§Example
println!("{}", value.red());
Source§

fn green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Green].

§Example
println!("{}", value.green());
Source§

fn yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Yellow].

§Example
println!("{}", value.yellow());
Source§

fn blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Blue].

§Example
println!("{}", value.blue());
Source§

fn magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Magenta].

§Example
println!("{}", value.magenta());
Source§

fn cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Cyan].

§Example
println!("{}", value.cyan());
Source§

fn white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: White].

§Example
println!("{}", value.white());
Source§

fn bright_black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlack].

§Example
println!("{}", value.bright_black());
Source§

fn bright_red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightRed].

§Example
println!("{}", value.bright_red());
Source§

fn bright_green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightGreen].

§Example
println!("{}", value.bright_green());
Source§

fn bright_yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightYellow].

§Example
println!("{}", value.bright_yellow());
Source§

fn bright_blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlue].

§Example
println!("{}", value.bright_blue());
Source§

fn bright_magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.bright_magenta());
Source§

fn bright_cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightCyan].

§Example
println!("{}", value.bright_cyan());
Source§

fn bright_white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightWhite].

§Example
println!("{}", value.bright_white());
Source§

fn bg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the background set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like on_red() and on_green(), which have the same functionality but are pithier.

§Example

Set background color to red using fg():

use yansi::{Paint, Color};

painted.bg(Color::Red);

Set background color to red using on_red().

use yansi::Paint;

painted.on_red();
Source§

fn on_primary(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Primary].

§Example
println!("{}", value.on_primary());
Source§

fn on_fixed(&self, color: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Fixed].

§Example
println!("{}", value.on_fixed(color));
Source§

fn on_rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Rgb].

§Example
println!("{}", value.on_rgb(r, g, b));
Source§

fn on_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Black].

§Example
println!("{}", value.on_black());
Source§

fn on_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Red].

§Example
println!("{}", value.on_red());
Source§

fn on_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Green].

§Example
println!("{}", value.on_green());
Source§

fn on_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Yellow].

§Example
println!("{}", value.on_yellow());
Source§

fn on_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Blue].

§Example
println!("{}", value.on_blue());
Source§

fn on_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Magenta].

§Example
println!("{}", value.on_magenta());
Source§

fn on_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Cyan].

§Example
println!("{}", value.on_cyan());
Source§

fn on_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: White].

§Example
println!("{}", value.on_white());
Source§

fn on_bright_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlack].

§Example
println!("{}", value.on_bright_black());
Source§

fn on_bright_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightRed].

§Example
println!("{}", value.on_bright_red());
Source§

fn on_bright_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightGreen].

§Example
println!("{}", value.on_bright_green());
Source§

fn on_bright_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightYellow].

§Example
println!("{}", value.on_bright_yellow());
Source§

fn on_bright_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlue].

§Example
println!("{}", value.on_bright_blue());
Source§

fn on_bright_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.on_bright_magenta());
Source§

fn on_bright_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightCyan].

§Example
println!("{}", value.on_bright_cyan());
Source§

fn on_bright_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightWhite].

§Example
println!("{}", value.on_bright_white());
Source§

fn attr(&self, value: Attribute) -> Painted<&T>

Enables the styling Attribute value.

This method should be used rarely. Instead, prefer to use attribute-specific builder methods like bold() and underline(), which have the same functionality but are pithier.

§Example

Make text bold using attr():

use yansi::{Paint, Attribute};

painted.attr(Attribute::Bold);

Make text bold using using bold().

use yansi::Paint;

painted.bold();
Source§

fn bold(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Bold].

§Example
println!("{}", value.bold());
Source§

fn dim(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Dim].

§Example
println!("{}", value.dim());
Source§

fn italic(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Italic].

§Example
println!("{}", value.italic());
Source§

fn underline(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Underline].

§Example
println!("{}", value.underline());

Returns self with the attr() set to [Attribute :: Blink].

§Example
println!("{}", value.blink());

Returns self with the attr() set to [Attribute :: RapidBlink].

§Example
println!("{}", value.rapid_blink());
Source§

fn invert(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Invert].

§Example
println!("{}", value.invert());
Source§

fn conceal(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Conceal].

§Example
println!("{}", value.conceal());
Source§

fn strike(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Strike].

§Example
println!("{}", value.strike());
Source§

fn quirk(&self, value: Quirk) -> Painted<&T>

Enables the yansi Quirk value.

This method should be used rarely. Instead, prefer to use quirk-specific builder methods like mask() and wrap(), which have the same functionality but are pithier.

§Example

Enable wrapping using .quirk():

use yansi::{Paint, Quirk};

painted.quirk(Quirk::Wrap);

Enable wrapping using wrap().

use yansi::Paint;

painted.wrap();
Source§

fn mask(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Mask].

§Example
println!("{}", value.mask());
Source§

fn wrap(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Wrap].

§Example
println!("{}", value.wrap());
Source§

fn linger(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Linger].

§Example
println!("{}", value.linger());
Source§

fn clear(&self) -> Painted<&T>

👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear(). The clear() method will be removed in a future release.

Returns self with the quirk() set to [Quirk :: Clear].

§Example
println!("{}", value.clear());
Source§

fn resetting(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Resetting].

§Example
println!("{}", value.resetting());
Source§

fn bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Bright].

§Example
println!("{}", value.bright());
Source§

fn on_bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: OnBright].

§Example
println!("{}", value.on_bright());
Source§

fn whenever(&self, value: Condition) -> Painted<&T>

Conditionally enable styling based on whether the Condition value applies. Replaces any previous condition.

See the crate level docs for more details.

§Example

Enable styling painted only when both stdout and stderr are TTYs:

use yansi::{Paint, Condition};

painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);
Source§

fn new(self) -> Painted<Self>
where Self: Sized,

Create a new Painted with a default Style. Read more
Source§

fn paint<S>(&self, style: S) -> Painted<&Self>
where S: Into<Style>,

Apply a style wholesale to self. Any previous style is replaced. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more