Feedback on JSON Schema validation library

Hey folks,

I'm reworking the API of my Rust jsonschema crate and want to ensure that the updated API is ergonomic and easy to use.

I've drafted a proposal for the updated API design and would love to hear your feedback. Does it feel idiomatic and easy to use within the Rust ecosystem? Are there any improvements or changes that could enhance the developer experience?

You can find the full writeup of the proposed API changes here: Version `1.0` API · Stranger6667/jsonschema-rs · Discussion #475 · GitHub

And here is the top-level API:

// Boolean result (panics on invalid schema)
async fn is_valid<J: Json>(schema: &J, instance: &J) -> bool
// Boolean result (errors on invalid schema)
async fn try_is_valid<J: Json>(schema: &J, instance: &J) -> Result<bool, BuildError>
// The first error (panics on invalid schema)
async fn validate<J: Json>(schema: &J, instance: &J) -> Result<(), ValidationError>
// The first error (errors on invalid schema)
async fn try_validate<J: Json>(schema: &J, instance: &J) -> Result<Result<(), ValidationError>, BuildError>
// Iterate over all errors (panics on invalid schema)
async fn iter_errors<'s, 'i, J: Json>(
    schema: &'s J,
    instance: &'i J,
) -> ValidationErrorIter<'static, 'i, J>
// Iterate over all errors (errors on invalid schema)
async fn try_iter_errors<'s, 'i, J: Json>(
    schema: &'s J,
    instance: &'i J,
) -> Result<ValidationErrorIter<'static, 'i, J>, BuildError>
// Structured output per the JSON Schema output formats (panics on invalid schema)
async fn evaluate<'i, J: Json>(
    instance: &'i J,
    schema: &J,
) -> Output<'static, 'i, J>
// Structured output per the JSON Schema output formats (errors on invalid schema)
async fn try_evaluate<'i, J: Json>(
    instance: &J,
    schema: &J,
) -> Result<Output<'static, 'i, J>, BuildError>

So it can be used like this:

use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let schema = json!({"type": "integer"});
    let instance = json!("a");
    assert!(!jsonschema::is_valid(&instance, &schema).await);
    jsonschema::validate(&instance, &schema).await?;
    for error in jsonschema::iter_errors(&instance, &schema).await {
        println!("{}", error);
    }
    let verbose = jsonschema::evaluate(&instance, &schema).await.verbose();
    let serialized = serde_json::to_string(&verbose)?;

    // Build once, reuse many times
    let validator = jsonschema::validator_for(&schema).await?;
    assert!(validator.is_valid(&instance));
    validator.validate(&instance)?;
    for error in validator.iter_errors(&instance) {
        println!("{}", error);
    }
    let verbose = validator.evaluate(&instance).verbose();
    Ok(())
}

The blocking API is available via the blocking module (similar to how reqwest does it).

Please take a moment to review the plans and share your opinions or suggestions.

Thanks for your help!