0

I wrote a simple program to test Cloudflare's wirefilter, here is an example that works.

use wirefilter::{ExecutionContext, Scheme};

lazy_static::lazy_static! {
    static ref SCHEME: Scheme = Scheme! {
        port: Int
    };
}

#[derive(Debug)]
struct MyStruct {
    port: i32,
}

impl MyStruct {
    fn scheme() -> &'static Scheme {
        &SCHEME
    }

    fn execution_context(&self) -> Result<ExecutionContext, failure::Error> {
        let mut ctx = ExecutionContext::new(Self::scheme());
        ctx.set_field_value("port", self.port)?;

        Ok(ctx)
    }
}

fn main() -> Result<(), failure::Error> {
    let data: Vec<MyStruct> = (0..10).map(|i| MyStruct { port: i as i32 }).collect();
    let scheme = MyStruct::scheme();
    let ast = scheme.parse("port in {2 5}")?;
    let filter = ast.compile();

    for i in data
        .iter()
        .filter(|d| filter.execute(&d.execution_context().unwrap()).unwrap())
    {
        println!("{:?}", i);
    }

    Ok(())
}

this will print:

MyStruct { port: 2 }
MyStruct { port: 5 }

If I create the vector data after I validate the schema, the borrowing system will start to complain.

I would like to validate the user input "port in {2 5}" before the creation of that vector which is an expensive operation, is there any way to do it?

The second version of the code is:

use wirefilter::{ExecutionContext, Scheme};

lazy_static::lazy_static! {
    static ref SCHEME: Scheme = Scheme! {
        port: Int
    };
}

#[derive(Debug)]
struct MyStruct {
    port: i32,
}

impl MyStruct {
    fn scheme() -> &'static Scheme {
        &SCHEME
    }

    fn execution_context(&self) -> Result<ExecutionContext, failure::Error> {
        let mut ctx = ExecutionContext::new(Self::scheme());
        ctx.set_field_value("port", self.port)?;

        Ok(ctx)
    }
}

fn main() -> Result<(), failure::Error> {
    let scheme = MyStruct::scheme();
    let ast = scheme.parse("port in {2 5}")?;
    let filter = ast.compile();

    let data: Vec<MyStruct> = (0..10).map(|i| MyStruct { port: i as i32 }).collect();
    for i in data.iter().filter(|d| filter.execute(&d.execution_context().unwrap()).unwrap()) {
        println!("{:?}", i);
    }

    Ok(())
}

which will fail with this message:

error[E0597]: `data` does not live long enough
  --> src/main.rs:33:14
   |
33 |     for i in data.iter().filter(|d| filter.execute(&d.execution_context().unwrap()).unwrap()) {
   |              ^^^^ borrowed value does not live long enough
...
38 | }
   | -
   | |
   | `data` dropped here while still borrowed
   | borrow might be used here, when `filter` is dropped and runs the destructor for type `wirefilter::filter::Filter<'_>`
   |
   = note: values in a scope are dropped in the opposite order they are defined

It seems that I can parse the query before data is created, but I cannot compile it.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Jayson Reis
  • 708
  • 5
  • 14

1 Answers1

1

You can separate the declaration of data from its assignment:

let data: Vec<MyStruct>;
let scheme = MyStruct::scheme();
let ast = scheme.parse("port in {2 5}")?;
let filter = ast.compile();
data = (0..10).map(|i| MyStruct { port: i as i32 }).collect();

The lifetime of data is the same as in the first version of your code, while the assignment happens at the same time as in the second version.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • Cool, thanks for the answer! Do you know how to make the same principle when you are working with a stream of data? I tried the same approach witha an interator and it does not seem to work too. ``` fn main() -> Result<(), failure::Error> { let data = generate_data(); ... let filtered = data.filter(|my_struct| filter.execute(&my_struct.execution_context().unwrap()).unwrap()); Ok(()) } fn generate_data() -> impl Iterator { (0..100).map(|port| MyStruct { port }) } ``` – Jayson Reis Apr 28 '19 at 10:50
  • @JaysonReis The code is not readable in a comment, and "it does not seem to work" is not a useful problem description. Please ask a new question, possibly referencing this question if appropriate. – Sven Marnach Apr 28 '19 at 11:14
  • You are right, I will re-write the code and post another question. – Jayson Reis Apr 28 '19 at 14:56