[Solved] Need help for function pointer signature

I am trying to build a library for form validation and of course for learning. Unfortunately, I got stuck on this function pointer signature problem for quite a while. Besides here, I don't know where should I got help on problems related to rust.

Here is a snippet to show the problem I got. There has a struct to represent a field which allow users to pass different functions to validate data during field initiation. To save users' time, I would like to make a few validation functions as default choices. Of course, users should able to override the validation functions if necessary.

Here is the version I would like to make it works:

#[cfg(test)]

mod tests {
  #[test]
  fn it_works() {
    pub struct Errrr{}
    struct FakeField<'a, 'd, T>{
      pub id: i8,
      pub min_len: Option<usize>,
      pub validator_lst: Box<[&'a Fn(&Self, &'d Option<T>) -> Result<(), Errrr>]>,
    };

    pub trait Validate<'d, T> {
      fn validate(&self, data: &'d Option<T>) -> Result<(), Errrr>;

    };

    impl<'a, 'd, T> FakeField<'a, 'd, T>{
      fn validate(&self, data: &'d Option<T>) -> Result<(), Errrr> {
        for field_validate_fxn in self.validator_lst.as_ref() {
          if let Result::Err(err) = field_validate_fxn(&self, data) {
            return Result::Err(err);
          }
        }
        Result::Ok(())
      }

      fn validate_min_len(&self, data: &'d Option<String>) -> Result<(), Errrr> {
        if self.min_len.is_none() {
          return Result::Ok(());
        }
        match data.as_ref().map(|s| s.len()).unwrap() {
          data_len if data_len < self.min_len.unwrap() => Result::Err(
            Errrr{}
            ),
          _ => Result::Ok(()),
        }
      }

    }

    impl<'a, 'd, T> Default for FakeField<'a, 'd, T> {
      fn default() -> Self {
        FakeField {
          id: 2,
          min_len: Some(1),
          // The following line has problem
          validator_lst: Box::new([&Self::validate_min_len,])
        }
      }
    }

    let _fake_field: FakeField<String> = FakeField{
        id: 3,
        min_len: None,
        ..Default::default()
    };
  }
}

Here is the error:

required for the cast to the object type dyn for&lt;'r&gt; std::ops::Fn(&amp;'r tests::it_works::FakeField&lt;'_, '_, T&gt;, &amp;std::option::Option&lt;T&gt;) -&gt; std::result::Result&lt;(), tests::it_works::Errrr&gt;

Here is the version which works, but not exactly I want:

#[cfg(test)]

mod tests {
  #[test]
  fn it_works() {
    pub struct Errrr{}
    struct FakeField<'a, 'd, T>{
      pub id: i8,
      pub min_len: Option<usize>,
      pub validator_lst: Box<[&'a Fn(&Self, &'d Option<T>) -> Result<(), Errrr>]>,
    };

    pub trait Validate<'d, T> {
      fn validate(&self, data: &'d Option<T>) -> Result<(), Errrr>;

    };

    impl<'a, 'd, T> FakeField<'a, 'd, T>{
      fn validate(&self, data: &'d Option<T>) -> Result<(), Errrr> {
        for field_validate_fxn in self.validator_lst.as_ref() {
          if let Result::Err(err) = field_validate_fxn(&self, data) {
            return Result::Err(err);
          }
        }
        Result::Ok(())
      }

      fn validate_min_len(&self, data: &'d Option<String>) -> Result<(), Errrr> {
        if self.min_len.is_none() {
          return Result::Ok(());
        }
        match data.as_ref().map(|s| s.len()).unwrap() {
          data_len if data_len < self.min_len.unwrap() => Result::Err(
            Errrr{}
            ),
          _ => Result::Ok(()),
        }
      }

    }

    impl<'a, 'd, T> Default for FakeField<'a, 'd, T> {
      fn default() -> Self {
        FakeField {
          id: 2,
          min_len: Some(1),
          // I would like to set a few functions as default validation function
          validator_lst: Box::new([])
        }
      }
    }

    let _fake_field: FakeField<String> = FakeField{
        id: 3,
        min_len: None,
        ..Default::default()
    };
  }
}

Does anyone have any clues? Thanks a lot.

Hi, welcome to user.rust-lang!!!

I can't promise that I will be able to solve your problem, but in any case, your error message is really unreadable, and you are missing the actual error...

required for the cast... -> What's required for the cast? The actual error should come before the required part.

The problem is that your Default impl claims it can produce any FakeField<T>, but it can really only produce a FakeField<String>. You could change it to this:

    impl<'a, 'd> Default for FakeField<'a, 'd, String> {
      fn default() -> Self {
        FakeField {
          id: 2,
          min_len: Some(1),
          validator_lst: Box::new([&Self::validate_min_len,])
        }
      }
    }
1 Like

That is the exact err output I got from compiler. I don't know if it is just me or not. I don't feel the following msg is not helpful to me.

error[E0631]: type mismatch in function arguments
  --> src/lib.rs:50:36
   |
30 |       fn validate_min_len(&self, data: &'d Option<String>) -> Result<(), Errrr> {
   |       ------------------------------------------------------------------------- found signature of `for<'r> fn(&'r tests::it_works::FakeField<'_, '_, T>, &std::option::Option<std::string::String>) -> _`
...
50 |           validator_lst: Box::new([&Self::validate_min_len,])
   |                                    ^^^^^^^^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r tests::it_works::FakeField<'_, '_, T>, &std::option::Option<T>) -> _`
   |
   = note: required for the cast to the object type `dyn for<'r> std::ops::Fn(&'r tests::it_works::FakeField<'_, '_, T>, &std::option::Option<T>) -> std::result::Result<(), tests::it_works::Errrr>`

error[E0631]: type mismatch in function arguments
  --> src/lib.rs:50:36
   |
30 |       fn validate_min_len(&self, data: &'d Option<String>) -> Result<(), Errrr> {
   |       ------------------------------------------------------------------------- found signature of `for<'r> fn(&'r tests::it_works::FakeField<'_, '_, T>, &std::option::Option<std::string::String>) -> _`
...
50 |           validator_lst: Box::new([&Self::validate_min_len,])
   |                                    ^^^^^^^^^^^^^^^^^^^^^^^ expected signature of `fn(&tests::it_works::FakeField<'_, '_, T>, &std::option::Option<T>) -> _`
   |
   = note: required for the cast to the object type `dyn for<'r> std::ops::Fn(&'r tests::it_works::FakeField<'_, '_, T>, &std::option::Option<T>) -> std::result::Result<(), tests::it_works::Errrr>`

That works! Thanks a lot. I feel so welcome in this community. Rust rocks! Thanks, guys.

I understand that the error messages are sometimes to be desired, but at least this says that the problem i the type mismatch in the function arguments, which helps a bit. It also shows the exact part of the line which is problematic. That helps narrowing it down a bit.

Glad it's working! Happy coding.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.