Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Edge cases involving non-public constraint types #3895

Open
drganjoo opened this issue Oct 29, 2024 · 0 comments
Open

Edge cases involving non-public constraint types #3895

drganjoo opened this issue Oct 29, 2024 · 0 comments
Labels
server Rust server SDK

Comments

@drganjoo
Copy link
Contributor

drganjoo commented Oct 29, 2024

Missing From Implementation

Consider the following model:

service SampleService {
    operations: [SampleOp]
}

@http(uri: "/sample", method: "POST")
operation SampleOp {
    input := {
        items: ItemMap
    }
    errors: [ValidationException]
}

@length(min: 0, max: 65535)
string ItemName
string ItemDescription

@length(min: 1, max: 100)
map ItemMap {
    key: ItemName,
    value: ItemListA
}

list ItemListA { 
    member: ItemListB
}

list ItemListB {
    member: ItemDescription
}

An SDK generated with publicConstrainedTypes set to false does not compile and raises the following error:

error[E0277]: the trait bound `HashMap<std::string::String, Vec<Vec<std::string::String>>>: From<ItemMap>` is not satisfied
   --> src/input.rs:136:55

This error occurs because SampleOpInput is defined as a HashMap with String as the key:

pub struct SampleOpInput {
    #[allow(missing_docs)] // documentation missing in model
    pub items: ::std::option::Option<
        ::std::collections::HashMap<
            ::std::string::String,
            ::std::vec::Vec<::std::vec::Vec<::std::string::String>>,
        >,
    >,
}

The method build_enforcing_all_constraints attempts to construct SampleOpInput by invoking the From implementation for ItemMap. However, the generated implementation uses ItemName (not String) as the key type for the HashMap:

impl ::std::convert::From<ItemMap> 
    for ::std::collections::HashMap<
        crate::model::ItemName,
        ::std::vec::Vec<::std::vec::Vec<::std::string::String>>,
    >

An additional From<ItemMap> needs to be generated:

impl ::std::convert::From<ItemMap>
    for ::std::collections::HashMap<
        ::std::string::String,
        ::std::vec::Vec<::std::vec::Vec<::std::string::String>>,
    >
{
    fn from(value: ItemMap) -> Self {
        value
            .into_inner()
            .into_iter()
            .map(|(k, v)| (k.into(), v))
            .collect()
    }
}

A directly constrained list with indirectly constrained map

Consider the following model:

operation SampleOp {
    input := {
        items: ItemList
    }
}

@length(min: 1 max: 100)
list ItemList {
    member: Item
}
map Item {
    key: ItemName
    value: ItemDescription
}

This results in non-compilable code:

93 |         value.into_inner().into_iter().map(|v| v.into()).collect()
   |                                                  ^^^^ the trait `From<HashMap<ItemName, std::string::String>>` is not implemented for `HashMap<std::string::String, std::string::String>`, which is required by `HashMap<ItemName, std::string::String>: Into<_>`

This happens because ItemList is defined as:

pub(crate) struct ItemList(
    pub(crate) 
        ::std::vec::Vec<::std::collections::HashMap<crate::model::ItemName, ::std::string::String>>,
);

Where as the TryFrom implementation assumes that the HashMap has String as key instead of ItemName:

impl ::std::convert::From<ItemList>
    for ::std::vec::Vec<::std::collections::HashMap<::std::string::String, ::std::string::String>>
{
    fn from(value: ItemList) -> Self {
        value.into_inner().into_iter().map(|v| v.into()).collect()
    }
}

Constrained map with a non-constrained list that has a constrained list as member

@length(min: 1 max: 100)
map ItemMap {
    key: ItemName,
    value: ItemListA
}
list ItemListA {
    member: ItemListB
}
@length(min: 1 max: 100)
list ItemListB {
    member: ItemDescription
}

Results in a compilation error on v.into() in the following From<ItemMap> implementation:

impl ::std::convert::From<ItemMap>
    for ::std::collections::HashMap<
        ::std::string::String,
        ::std::vec::Vec<::std::vec::Vec<::std::string::String>>,
    >
{
    fn from(value: ItemMap) -> Self {
        value
            .into_inner()
            .into_iter()
            .map(|(k, v)| (k.into(), v.into()))
            .collect()
    }
}

Nested lists

@length(min: 1 max: 100)
  list ItemList {
      member: ItemA
  }
  list ItemA {
      member: ItemB
  }
  list ItemB {
      member: ItemName
  }

Results in an error in TryFrom<ItemsList> implementation at v.into().

pub(crate) struct ItemList(
    pub(crate) ::std::vec::Vec<::std::vec::Vec<::std::vec::Vec<crate::model::ItemName>>>,
);

impl ::std::convert::From<ItemList>
    for ::std::vec::Vec<::std::vec::Vec<::std::vec::Vec<::std::string::String>>>
{
    fn from(value: ItemList) -> Self {
        value.into_inner().into_iter().map(|v| v.into()).collect()
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
server Rust server SDK
Projects
None yet
Development

No branches or pull requests

1 participant