0

Playground

I have the following generated code (from flatbuffers schema):

pub trait TFilterData {
    fn get_text(&self) -> &str;
}

pub struct Table<'a> {
    pub buf: &'a [u8],
    pub loc: usize,
}

pub struct Data<'a> {
    pub _tab: Table<'a>,
}

pub struct MatchResult<'a> {
    pub _tab: Table<'a>,
}

pub struct FiltersByKeyword<'a> {
    pub _tab: Table<'a>,
}

pub struct KeywordByFilter<'a> {
    pub _tab: Table<'a>,
}

pub struct BlockingFilter<'a> {
    pub _tab: Table<'a>,
}

impl TFilterData for BlockingFilter<'_> {
    fn get_text(&self) -> &str {
        todo!()
    }
}

impl<'a> MatchResult<'a> {
    pub fn blocking_filters(&self) -> Option<Vec<BlockingFilter<'a>>> {
        None
    }
}

impl<'a> FiltersByKeyword<'a> {
    pub fn filters(&self) -> Option<Vec<MatchResult<'a>>> {
        None
    }

    pub fn keyword(&self) -> String {
        "".to_owned()
    }
}

impl<'a> Data<'a> {
    pub fn keyword_by_filter_list(&self) -> Option<Vec<KeywordByFilter<'a>>> {
        None
    }

    pub fn filters_by_keyword_list(&self) -> Option<Vec<FiltersByKeyword<'a>>> {
        None
    }
}

I have my own struct that owns it:

pub type RcedFilterDataVec = Vec<Rc<dyn TFilterData>>;

pub struct FlatBuffersIndex<'a> {
    data: Data<'a>,
    filter_by_keyword: HashMap<String, RcedFilterDataVec>, // keyword -> list of `TFilterData`s
    keyword_by_filter: HashMap<String, String>,            // Filter -> keyword
}

impl<'a> FlatBuffersIndex<'a> {
    pub fn new(buffer: &'a [u8]) -> Self {
        let data: Data<'a> = Data {
            _tab: Table {
                buf: buffer,
                loc: 0,
            },
        };

        let mut keyword_by_filter = HashMap::new();
        let mut filter_by_keyword = HashMap::new();
        if let Some(some_filters_by_keyword_list) = data.filters_by_keyword_list() {
            for key_value in some_filters_by_keyword_list {
                let mut filters = RcedFilterDataVec::new();

                // filters
                for each_match_result in key_value.filters().unwrap() {
                    // TODO: there is no sense in mixing of them as later matcher will have to separate them

                    // blocking
                    if let Some(some_blocking_filters) = each_match_result.blocking_filters() {
                        for each_blocking_filter in some_blocking_filters {
                            // actually we don't need BlockingFilter part more than RegExpFilter + FilterType
                            // let filter = each_blocking_filter.regexp_filter().clone();
                            let rc_filter = Rc::new(each_blocking_filter);
                            filters.push(rc_filter);
                            // TODO: add it!!! currently commented due to unclear lifetime issue
                        }
                    }

                    // ...
                }

                filter_by_keyword.insert(key_value.keyword().to_owned(), filters);
            }
        }

        FlatBuffersIndex {
            data,
            filter_by_keyword,
            keyword_by_filter,
        }
    }
}

When trying to iterate on it i have the following error output:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
   --> src/lib.rs:83:58
    |
83  |         if let Some(some_filters_by_keyword_list) = data.filters_by_keyword_list() {
    |                                                          ^^^^^^^^^^^^^^^^^^^^^^^
    |
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 72:6...
   --> src/lib.rs:72:6
    |
72  | impl<'a> FlatBuffersIndex<'a> {
    |      ^^
note: ...so that the types are compatible
   --> src/lib.rs:83:58
    |
83  |         if let Some(some_filters_by_keyword_list) = data.filters_by_keyword_list() {
    |                                                          ^^^^^^^^^^^^^^^^^^^^^^^
    = note: expected `&Data<'_>`
               found `&Data<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
   --> src/lib.rs:111:13
    |
111 |             filter_by_keyword,
    |             ^^^^^^^^^^^^^^^^^
    = note: expected `HashMap<_, Vec<Rc<(dyn TFilterData + 'static)>>>`
               found `HashMap<_, Vec<Rc<dyn TFilterData>>>`

Why isn't it clear for the compiler that it will live for 'a that seems to be ok here? How can i fix it?

PS. This is the flatbuffers IDL to generate the code:

namespace com.eyeo.adblockplus.fb;

table AbpFilter {
  filter_text: string (required); // Strings are UTF-8, [ubyte] might be needed. How will we have `String` without convertions then?
  filter_type: ushort;
}

table CommentFilter {
  filter: AbpFilter (required);
}

table InvalidFilter {
  filter: AbpFilter (required);
  reason: string (required);
}

table ActiveFilter {
  filter: AbpFilter (required);
  sitekeys: [string];
  domain_separator: string (required);
  domain_source: string;
  domain_source_is_lower_case: bool;
}

table RegExpFilter {
  active_filter: ActiveFilter (required);
  third_party: bool;
  content_type: uint;
  pattern: string;
  rewrite: string;
}

// Probably we don't really need subclasses of RegExpFilter for matching
// as we have RegExpFilter + FilterType to be used by Matcher when matching
table BlockingFilter {
  regexp_filter: RegExpFilter (required);
  collapse: bool; // probably unneeded
  csp: string; // probably unneeded
}

table AllowingFilter {
  regexp_filter: RegExpFilter (required);
}

table MatchResult {
  blocking_filters: [BlockingFilter];
  allowing_filters: [AllowingFilter];
}

// non-abstract filters (leafs)
// vector of union's is not supported unfortunately,
// thus we can't declare `filters: [FilterUnion]` in `struct` or `table`. Can we?
// union FilterUnion {
//   CommentFilter,
//   InvalidFilter,
// }

table KeywordByFilter {
  filter_text: string (required, key);
  keyword: string (required);
}

table FiltersByKeyword {
  keyword: string (key);
  filters: [MatchResult];
}

table Storage {
  invalid_filters: [InvalidFilter];
  comment_filters: [CommentFilter];
}

table Data {
  filters: [MatchResult];
  keyword_by_filter_list: [KeywordByFilter];
  filters_by_keyword_list: [FiltersByKeyword];
  storage: Storage;
}

root_type Data;

PPS. i've found it happens only when iterating over another vector from flatbuffers collection (each_match_result.blocking_filters() or each_match_result.allowing_filters()) and adding it to a new filters vector filters that is put into filter_by_keyword:

if let Some(some_blocking_filters) = each_match_result.blocking_filters() {
                        for each_blocking_filter in some_blocking_filters {
                            // actually we don't need BlockingFilter part more than RegExpFilter + FilterType
                            filters.push(Rc::new(each_blocking_filter.regexp_filter()));
                        }
                    }

Here is how this other collections is declared:

pub fn blocking_filters(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<BlockingFilter<'a>>>> {
    self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<BlockingFilter<'a>>>>>(MatchResult::VT_BLOCKING_FILTERS, None)
  }
trent
  • 25,033
  • 7
  • 51
  • 90
4ntoine
  • 19,816
  • 21
  • 96
  • 220
  • Can you edit the question to provide a self-sufficient example that we can run to reproduce the issue? – user4815162342 Mar 22 '21 at 07:41
  • The error is saying there's a `HashMap` dictating that values must have a `'static` lifetime. Where is that type defined? – kmdreko Mar 22 '21 at 07:45
  • @user4815162342 that's i've updated the question – 4ntoine Mar 22 '21 at 08:28
  • @kmdreko The OP's code contains `let mut filter_by_keyword = HashMap::new()`, perhaps the inference is misled by something? – user4815162342 Mar 22 '21 at 08:44
  • I was able to extract the minimum code snippet to repro: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7791396b43f85575f09dd5b30539725f – 4ntoine Mar 22 '21 at 09:28
  • 2
    The dupes in this case suggest [adding a lifetime to `RcedFilterDataVec`](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8495ae572f097014976ba32c18f1a8cf). – trent Mar 22 '21 at 15:46

0 Answers0