the trait bound `Option<i32>: ToSchema` is not satisfied
Closed this issue · 31 comments
Hi. Im trying out the new generic support for 0.1.0-rc.0 and I am running into issues updating my code.
By using the following code, I am getting an error when I'm trying to create a struct
pub type optionTransaction = IdentifiableTransactionBase<Transaction, Option<Uuid>>;
pub type nonOptionTransaction = IdentifiableTransactionBase<Transaction, Uuid>;
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
pub struct IdentifiableTransactionBase<B: ToSchema, I: ToSchema> {
/// Id representing the full transaction.
pub transaction_id: I,
#[serde(flatten)]
pub base: B,
}
the trait bound 'uuid::Uuid: ToSchema' is not satisfied
This was not an issue before when using aliases. I apologise if this was already discussed somewhere and I have missed it :)
It might be a problem in the the rc itself. I tried the following in the master
in to utoipa-config/config-test-crate/
and it works no errors:
pub type optionTransaction = IdentifiableTransactionBase<Transaction, Option<Uuid>>;
pub type nonOptionTransaction = IdentifiableTransactionBase<Transaction, Uuid>;
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
pub struct IdentifiableTransactionBase<B: ToSchema, I: ToSchema> {
/// Id representing the full transaction.
pub transaction_id: I,
#[serde(flatten)]
pub base: B,
}
It might be issue that is fixed here #1079
Hi. Thanks for the swift reply.
I actually tried master as well but got bombarded with 1000s of errors :D
Will atempt again and report back the results.
😅 heh, yeah there are plenty of changes. Though eventually I will write some sort of migration guide about the fundamental changes once I get that far.
Yeah can confirm its a problem with the rc.
Created minimal reproducible example
[package]
name = "utoipatest"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
uuid = { version = "1.10.0", features = ["serde", "v4"] }
utoipa = { version = "5.0.0-rc.0", features = ["axum_extras", "time", "uuid", "decimal_float", "config"] }
use utoipa::ToSchema;
use uuid::Uuid;
pub type optionTransaction = IdentifiableTransactionBase<i32, Option<Uuid>>;
pub type nonOptionTransaction = IdentifiableTransactionBase<i32, Uuid>;
#[derive(Clone, Debug, ToSchema)]
pub struct IdentifiableTransactionBase<B: ToSchema, I: ToSchema> {
/// Id representing the full transaction.
pub transaction_id: I,
pub base: B,
}
fn main() {
println!("Hello, world!");
let trans = nonOptionTransaction {
transaction_id: Uuid::new_v4(),
base: 1,
};
}
And getting
error[E0277]: the trait bound `uuid::Uuid: ToSchema` is not satisfied
--> src/main.rs:17:17
|
17 | let trans = nonOptionTransaction {
| ^^^^^^^^^^^^^^^^^^^^ the trait `ToSchema` is not implemented for `uuid::Uuid`
|
= help: the following other types implement trait `ToSchema`:
bool
char
isize
i8
i16
i32
i64
i128
and 13 others
note: required by a bound in `IdentifiableTransactionBase`
--> src/main.rs:8:56
|
8 | pub struct IdentifiableTransactionBase<B: ToSchema, I: ToSchema> {
| ^^^^^^^^ required by this bound in `IdentifiableTransactionBase`
But with master
utoipa = { git = "https://github.com/juhaku/utoipa.git", features = ["axum_extras", "time", "uuid", "decimal_float", "config"] }
and changing to pub struct IdentifiableTransactionBase<B, I> {
the code compiles fine :)
Apologies for the issue raised.
Will atempt to migrate my project to master and see if I get any luck. Thanks for the great work again!
No worries, great that you got it working.
Hello.
I am back and re-opening the issue. I hope thats okay, if not, I will close and create a new issue.
I am experiancing the same issue as before, but this time, not when I try to create an object, but rather when I try to define and enum using that type. This is happening in master.
Here is a reproducible example
Catgo.toml
[package]
name = "utoipatest"
version = "0.1.0"
edition = "2021"
[dependencies]
utoipa = {git = "https://github.com/juhaku/utoipa.git" }
main.rs
use utoipa::ToSchema;
pub type OptionFoo = FooStruct<Option<i32>>;
#[derive(ToSchema)]
pub struct FooStruct<B> {
pub foo: B,
}
#[derive(ToSchema)]
pub enum FoosEnum {
FooEnumThing(OptionFoo),
}
fn main() {
println!("Hello, world!");
}
Error
error[E0277]: the trait bound `Option<i32>: ToSchema` is not satisfied
--> src/main.rs:12:18
|
12 | FooEnumThing(OptionFoo),
| ^^^^^^^^^ the trait `ToSchema` is not implemented for `Option<i32>`, which is required by `FooStruct<Option<i32>>: ToSchema`
|
= help: the following other types implement trait `ToSchema`:
bool
char
isize
i8
i16
i32
i64
i128
and 14 others
note: required for `FooStruct<Option<i32>>` to implement `ToSchema`
--> src/main.rs:5:10
|
5 | #[derive(ToSchema)]
| ^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
6 | pub struct FooStruct<B> {
| ^^^^^^^^^^^^
= note: this error originates in the derive macro `ToSchema` (in Nightly builds, run with -Z macro-backtrace for more info)
Hope this helps :)
I am back and re-opening the issue. I hope thats okay
Yeah it is alright. And it does help indeed, 🙂 It is always good to have something concrete to reproduces or at least to point out the thing that does not wok to help with debugging.
I need to further investigate this a bit, I belive that I have missed the alias TypeTree
from some places like in the enum variant processing. I'll try to look into this as next thing on the list.
This is actually a different issue and is not related to the original aliases. This issue arises because of limitations on current generics implementation which does not implement ToSchema
for container types like Option<T>
, Vec<T>
, etc. because they are automatically inlined when they are used as types for fields or variants. The current solution does not actually know how to correctly handle those container types when they are used as generic arguments for types.
This actually is not a small fix, but rather some real engineering effort needs to be put into this in order to get the types correct (if possible). I'll try to see what can be done, nonetheless.
There is fix for this coming up in #1107 but with few limitations. tuples, slices and arrays cannot be used as generic arguments. This would need some internal changes that need to be addressed in future. From now on concrete types should work as well.
Note to above, for type aliases to correctly generate the schema they need to be registered in build.rs
with utoipa-config
. If not then the underlying type will not be correct schema even if it manages to generate one.
pub type OptionFoo = FooStruct<Option<i32>>; #[derive(ToSchema)] pub struct FooStruct<B> { pub foo: B, } #[derive(ToSchema)] pub enum FoosEnum { FooEnumThing(OptionFoo), }
This is amazing! Im always amazed how responsive you are to the community.
Is there a way to buy you a coffee? Did not find any link for that :)
Either way, it appears I still have a similar problem. This time with UUID again as in initial query. Probably should have tested this before hand and raised it as well, so apologies for the back and forth.
Here is a reproducable example
[package]
name = "utoipatest"
version = "0.1.0"
edition = "2021"
[dependencies]
utoipa = {git = "https://github.com/juhaku/utoipa.git" }
uuid = { version = "1.10.0", features = ["v4"] }
use utoipa::ToSchema;
use uuid::Uuid;
pub type OptionFoo = FooStruct<Uuid>;
#[derive(ToSchema)]
pub struct FooStruct<B> {
pub foo: B,
}
#[derive(ToSchema)]
pub enum FoosEnum {
FooEnumThing(OptionFoo),
}
fn main() {
// This is okay now. It did not work inittially when I raised the issue.
let a = OptionFoo { foo: uuid::Uuid::new_v4() };
}
error[E0277]: the trait bound `Uuid: ToSchema` is not satisfied
--> src/main.rs:13:18
|
13 | FooEnumThing(OptionFoo),
| ^^^^^^^^^ the trait `ToSchema` is not implemented for `Uuid`, which is required by `FooStruct<Uuid>: ToSchema`
|
= help: the following other types implement trait `ToSchema`:
bool
char
isize
i8
i16
i32
i64
i128
and 27 others
note: required for `FooStruct<Uuid>` to implement `ToSchema`
--> src/main.rs:6:10
|
6 | #[derive(ToSchema)]
| ^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
7 | pub struct FooStruct<B> {
| ^^^^^^^^^^^^
= note: this error originates in the derive macro `ToSchema` (in Nightly builds, run with -Z macro-backtrace for more info)
You need the uuid
feature flag for utiopa most likely.
[dependencies]
utoipa = {git = "https://github.com/juhaku/utoipa.git", feature = ["uuid"] }
uuid = { version = "1.10.0", features = ["v4"] }
This is amazing! Im always amazed how responsive you are to the community.
It just that I have now plenty of time 😄 I should really set the github sponsors up, I just haven't as of yet. But thanks anyways 🙂
You need the uuid feature flag for utiopa most likely.
Unfortunately, even after adding uuid feature flag it still has the same error :(
I have it in my main project and got the same error, just forgot to include it in the example :D
Ah, right, okay, now I know what is going on. This hit again another limitation of the current generics. The issue arises now in cases where a certain type should be treated as a primitive type but is an external type actually. That is, in general all schemas should implement ToSchema
and when it comes to Uuid
utoipa will check whether the type is a primitive type and tokenize it. If uuid
feature is enabled this check will be true in case of Uuid
type. However this only works with fields of a struct or enum variants but no on generic arguments since the generics is quite a new thing this wasn't considered there. This still needs some experimenting around possibilities.
The same is true with other external types and applies to them as well. These are chrono
's date time types pretty much all that can be enabled via appropriate feature flag.
The quick "fix" for your issue is to wrap it to a new type and use that as a generic argument.
#[derive(ToSchema)]
struct MyUuid(Uuid);
#[derive(ToSchema)]
pub struct FooStruct<B> {
pub foo: B,
}
let a = FooStruct {
foo: MyUuid(Uuid::new_v4())
}
@EinarasGar This PR #1110 will enhance the generics with support for allowing known third party types to be used as a generic argument fixing the issue you are encountering with.
Thanks again for taking a look! Very fast.
Unfortunately I still see the same error even with your provided example. Perhaps im missing something?
I verified that I am on latest commit fc22ddf
use utoipa::ToSchema;
#[derive(ToSchema)]
pub struct High<T> {
high: T,
}
#[derive(ToSchema)]
pub struct HighUuid(High<Option<uuid::Uuid>>);
fn main() {
}
[package]
name = "utoipatest"
version = "0.1.0"
edition = "2021"
[dependencies]
utoipa = {git = "https://github.com/juhaku/utoipa.git", feature = ["uuid"] }
uuid = { version = "1.10.0", features = ["v4"] }
warning: unused manifest key: dependencies.utoipa.feature
Checking utoipatest v0.1.0 (/workspace/test/utoipatest)
error[E0277]: the trait bound `Uuid: ToSchema` is not satisfied
--> src/main.rs:9:21
|
9 | pub struct HighUuid(High<Option<uuid::Uuid>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ToSchema` is not implemented for `Uuid`, which is required by `High<Option<Uuid>>: ToSchema`
|
= help: the following other types implement trait `ToSchema`:
bool
char
isize
i8
i16
i32
i64
i128
and 27 others
= note: required for `Option<Uuid>` to implement `ToSchema`
= note: 1 redundant requirement hidden
= note: required for `High<Option<Uuid>>` to implement `ToSchema`
error[E0277]: the trait bound `Uuid: ComposeSchema` is not satisfied
--> src/main.rs:9:21
|
9 | pub struct HighUuid(High<Option<uuid::Uuid>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ComposeSchema` is not implemented for `Uuid`, which is required by `High<Option<Uuid>>: ToSchema`
|
= help: the following other types implement trait `ComposeSchema`:
High<T>
HighUuid
Box<T>
Cow<'a, T>
HashMap<K, T>
BTreeMap<K, T>
HashSet<K>
BTreeSet<K>
and 7 others
= note: required for `Uuid` to implement `PartialSchema`
= note: required for `Option<Uuid>` to implement `ComposeSchema`
= note: 1 redundant requirement hidden
= note: required for `Option<Uuid>` to implement `PartialSchema`
= note: required for `Option<Uuid>` to implement `ToSchema`
= note: 1 redundant requirement hidden
= note: required for `High<Option<Uuid>>` to implement `ToSchema`
error[E0277]: the trait bound `Uuid: ToSchema` is not satisfied
--> src/main.rs:9:26
|
9 | pub struct HighUuid(High<Option<uuid::Uuid>>);
| ^^^^^^^^^^^^^^^^^^ the trait `ToSchema` is not implemented for `Uuid`, which is required by `Option<Uuid>: ToSchema`
|
= help: the following other types implement trait `ToSchema`:
bool
char
isize
i8
i16
i32
i64
i128
and 27 others
= note: required for `Option<Uuid>` to implement `ToSchema`
error[E0277]: the trait bound `Uuid: ComposeSchema` is not satisfied
--> src/main.rs:9:26
|
9 | pub struct HighUuid(High<Option<uuid::Uuid>>);
| ^^^^^^^^^^^^^^^^^^ the trait `ComposeSchema` is not implemented for `Uuid`, which is required by `Option<Uuid>: PartialSchema`
|
= help: the following other types implement trait `ComposeSchema`:
High<T>
HighUuid
Box<T>
Cow<'a, T>
HashMap<K, T>
BTreeMap<K, T>
HashSet<K>
BTreeSet<K>
and 7 others
= note: required for `Uuid` to implement `PartialSchema`
= note: required for `Option<Uuid>` to implement `ComposeSchema`
= note: 1 redundant requirement hidden
= note: required for `Option<Uuid>` to implement `PartialSchema`
note: required by a bound in `name`
--> /home/vscode/.cargo/git/checkouts/utoipa-797003a51754f4fd/fc22ddf/utoipa/src/lib.rs:403:21
|
403 | pub trait ToSchema: PartialSchema {
| ^^^^^^^^^^^^^ required by this bound in `ToSchema::name`
...
434 | fn name() -> Cow<'static, str> {
| ---- required by a bound in this associated function
error[E0277]: the trait bound `Uuid: ToSchema` is not satisfied
--> src/main.rs:9:33
|
9 | pub struct HighUuid(High<Option<uuid::Uuid>>);
| ^^^^^^^^^^ the trait `ToSchema` is not implemented for `Uuid`
|
= help: the following other types implement trait `ToSchema`:
bool
char
isize
i8
i16
i32
i64
i128
and 27 others
error[E0277]: the trait bound `Uuid: ComposeSchema` is not satisfied
--> src/main.rs:9:33
|
9 | pub struct HighUuid(High<Option<uuid::Uuid>>);
| ^^^^^^^^^^ the trait `ComposeSchema` is not implemented for `Uuid`, which is required by `Uuid: PartialSchema`
|
= help: the following other types implement trait `ComposeSchema`:
High<T>
HighUuid
Box<T>
Cow<'a, T>
HashMap<K, T>
BTreeMap<K, T>
HashSet<K>
BTreeSet<K>
and 7 others
= note: required for `Uuid` to implement `PartialSchema`
note: required by a bound in `name`
--> /home/vscode/.cargo/git/checkouts/utoipa-797003a51754f4fd/fc22ddf/utoipa/src/lib.rs:403:21
|
403 | pub trait ToSchema: PartialSchema {
| ^^^^^^^^^^^^^ required by this bound in `ToSchema::name`
...
434 | fn name() -> Cow<'static, str> {
| ---- required by a bound in this associated function
For more information about this error, try `rustc --explain E0277`.
error: could not compile `utoipatest` (bin "utoipatest") due to 12 previous errors
Perhaps cargo clean
will help? 🤔
I also tried cargo clean and even peeked into the code itself to verify that your changes are in.
Let me try to spin up a new dev container and reproduce it again :D
😮 That is so real, at least the one feature is wrong but not sure whether that actually has any impact.
Yeah just noticed and fixed axum_extras feature, but still same
Yeah, This is what it suppose to generate if you expand the ToSchema
macro on that HighUuid
type.
impl utoipa::__dev::ComposeSchema for HighUuid {
fn compose(
mut generics: Vec<utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>>,
) -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
utoipa::openapi::schema::RefBuilder::new()
.ref_location_from_schema_name(std::borrow::Cow::Owned(format!(
"{}_{}",
<High<Option<String>> as utoipa::ToSchema>::name(),
std::borrow::Cow::<String>::Owned(
[std::borrow::Cow::Owned(format!(
"{}_{}",
<Option<String> as utoipa::ToSchema>::name(),
std::borrow::Cow::<String>::Owned(
[<String as utoipa::ToSchema>::name(),].to_vec().join("_")
)
)),]
.to_vec()
.join("_")
)
)))
.into()
}
}
impl utoipa::ToSchema for HighUuid {
fn name() -> std::borrow::Cow<'static, str> {
std::borrow::Cow::Borrowed("HighUuid")
}
}
impl utoipa::__dev::SchemaReferences for HighUuid {
fn schemas(
schemas: &mut Vec<(
String,
utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>,
)>,
) {
schemas.extend([(
String::from(std::borrow::Cow::Owned(format!(
"{}_{}",
<High<Option<String>> as utoipa::ToSchema>::name(),
std::borrow::Cow::<String>::Owned(
[std::borrow::Cow::Owned(format!(
"{}_{}",
<Option<String> as utoipa::ToSchema>::name(),
std::borrow::Cow::<String>::Owned(
[<String as utoipa::ToSchema>::name(),].to_vec().join("_")
)
)),]
.to_vec()
.join("_")
)
))),
<High<Option<String>> as utoipa::__dev::ComposeSchema>::compose(
[<Option<String> as utoipa::__dev::ComposeSchema>::compose(
[<String as utoipa::PartialSchema>::schema()].to_vec(),
)]
.to_vec(),
),
)]);
<High<Option<String>> as utoipa::__dev::SchemaReferences>::schemas(schemas);
}
}
That's what I have in Cargo.lock
[[package]]
name = "utoipa"
version = "5.0.0-rc.0"
source = "git+https://github.com/juhaku/utoipa.git?branch=master#fc22ddfd22591aa2dd110e65a166f9391df23171"
dependencies = [
"indexmap",
"serde",
"serde_json",
"utoipa-gen",
]
[[package]]
name = "utoipa-gen"
version = "5.0.0-rc.0"
source = "git+https://github.com/juhaku/utoipa.git?branch=master#fc22ddfd22591aa2dd110e65a166f9391df23171"
dependencies = [
"proc-macro2",
"quote",
"regex",
"syn",
"uuid",
]
[[package]]
name = "utoipa-swagger-ui"
version = "7.1.1-rc.0"
source = "git+https://github.com/juhaku/utoipa.git?branch=master#fc22ddfd22591aa2dd110e65a166f9391df23171"
dependencies = [
"axum",
"mime_guess",
"regex",
"rust-embed",
"serde",
"serde_json",
"url",
"utoipa",
"zip",
]
Does the devcontainers
use local cache for the the crates.io
index or is it global on your system? If it is global you could try to remove the record from the caced index on your machine.
registry/src/index.crates.io-6f17d22bba15001f
❯ ls -l | grep utoipa
drwxr-xr-x - juha 18 Apr 00:49 utoipa-4.0.0
drwxr-xr-x - juha 29 Aug 17:08 utoipa-4.2.3
drwxr-xr-x - juha 18 Apr 00:49 utoipa-gen-4.0.0
drwxr-xr-x - juha 29 Aug 17:08 utoipa-gen-4.3.0
drwxr-xr-x - juha 18 Apr 00:49 utoipa-swagger-ui-4.0.0
drwxr-xr-x - juha 8 Sep 10:59 utoipa-swagger-ui-7.1.0
registry/src/index.crates.io-6f17d22bba15001f
❯ cd ../../cache
.cargo/registry/cache
❯ ls -l | grep utoipa
.cargo/registry/cache
❯ cd index.crates.io-6f17d22bba15001f
registry/cache/index.crates.io-6f17d22bba15001f
❯ ls -l | grep utoipa
.rw-r--r-- 54k juha 18 Apr 00:49 utoipa-4.0.0.crate
.rw-r--r-- 55k juha 29 Aug 17:08 utoipa-4.2.3.crate
.rw-r--r-- 141k juha 18 Apr 00:49 utoipa-gen-4.0.0.crate
.rw-r--r-- 143k juha 29 Aug 17:08 utoipa-gen-4.3.0.crate
.rw-r--r-- 4,4M juha 18 Apr 00:49 utoipa-swagger-ui-4.0.0.crate
.rw-r--r-- 26k juha 8 Sep 10:59 utoipa-swagger-ui-7.1.0.crate
registry/cache/index.crates.io-6f17d22bba15001f
I found the issue.
Im too new to rust to understand why, but my cargo.lock was like this
[[package]]
name = "utoipa-gen"
version = "5.0.0-rc.0"
source = "git+https://github.com/juhaku/utoipa.git?branch=master#fc22ddfd22591aa2dd110e65a166f9391df23171"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
Adding utoipa-gen = { git = "https://github.com/juhaku/utoipa.git", branch="master", features = ["regex","uuid"] }
to dependencies fixed it
Good that you got it solved. Yeah it is hard to tell from here what is going on as I am not running on devcontainers.
Also one command also might be useful sometimes is cargo update
it will update the Or actually it will update the Cargo.lock file exactly. https://doc.rust-lang.org/cargo/commands/cargo-update.htmlcrates.io
index on your local machine.
Most likely that should have done it. As in utoipa
does not have specifically regex
feature but it will come as a dependency for utoipa-gen
when axum_extras
feature flag is there.
Yeah this is odd. Apologies for all the invested time.
The selling point of dev containers is that its supposed to be a fresh reproducible environment, so thats why I tried to use it.
Either way, still seems to be a problem with Enums, even though it works fine with structs
But at this point, I think you're better off spending your time on other tasks :D Already invested too much time with me
Actually it works, the issue is that Rust type alias you are using there. If you want to use type aliases you need to register them with utoipa-config
for utoipa
. If you give the High<Uuid>
directly as a value for FooEnumThing
variant it will work as well.
See the more about the config https://github.com/juhaku/utoipa/tree/master/utoipa-config
https://github.com/juhaku/utoipa/tree/master/utoipa-config/config-test-crate
Ahhh I see. Makes sense!
Well that solves it. I think its the last remaining thing I had left for my migration.
Thank you for the 10th time. You should really consider adding sponsor button somewhere in your github :)
Happy to help, haha 😆 perhaps I should.