Builder pattern that borrows from self

Hi folks,

I have a few structs with lifetimes (First and Second) with parsed data. And I have functions parse_data to parse data (I use split_once as a good example because it leaves lifetime).

Individually the First and Second work great:

let data = "a/b/c/d/e/f/g".to_owned();
let cf = "/".to_owned();
let x = First::parse_data(&data, &cf);

The problem is when I want to use them in a large struct in a form of a building pattern:

let data = "a/b/c/d/e/f/g".to_owned();
let cf = "/".to_owned();
let x = Everything::new(&data, &cf).set_first();

I get lifetime issues. Easy solution would be to modify First::parse_data and Second::parse_data so they take owned arguments but they're more useful when they just borrow.

Could you please tell me if there is another solution?

Thank you.

Full code:

#[derive(Clone, Debug, Default, Eq, PartialEq)]
struct First<'a> {
    parsed: &'a str,
}
impl<'a, 'b> First<'a> {
    fn parse_data(data: &'a str, cf: &'b str) -> (Option<Self>, String) {
        match data.split_once(cf) {
            None => (None, data.to_owned()),
            Some((parsed,out)) => (Some(Self { parsed }), out.to_owned() )
        }
    }
}

#[derive(Clone, Debug, Default, Eq, PartialEq)]
struct Second<'a> {
    parsed: &'a str,
}
impl<'a, 'b> Second<'a> {
    fn parse_data(data: &'a str, cf: &'b str) -> (Option<Self>, String) {
        match data.split_once(cf) {
            None => (None, data.to_owned()),
            Some((parsed,out)) => (Some(Self { parsed }), out.to_owned() )
        }
    }
}

struct MyError;

#[derive(Clone, Debug, Default, Eq, PartialEq)]
struct Everything<'a> {
    first:  Option<First<'a>>,
    second: Option<First<'a>>,
    unparsed: String,
    cf: String,
}
impl<'a, 'b> Everything<'a> {
    fn new(data: &'a str, cf: &'b str) -> Self {
        Self {
            unparsed: data.to_owned(),
            cf: cf.to_owned(),
            ..Default::default()
        }
    }
    fn set_first(mut self) -> Result<Self, MyError> {
        ////////////////////////////////////////////  THIS IS A PROBLEM
        if let (first, unparsed) = First::parse_data(&self.unparsed, &self.cf) {
            self.first = first;
            self.unparsed = unparsed;
            Ok(self)
        } else {
            Err(MyError)
        }
    }
}

fn main() {
    // this is fine:
    // let data = "a/b/c/d/e/f/g".to_owned();
    // let cf = "/".to_owned();
    // let x = First::parse_data(&data, &cf);
    // let y = Second::parse_data(&data, &cf);

    // this is a problem:
    let data = "a/b/c/d/e/f/g".to_owned();
    let cf = "/".to_owned();
    let x = Everything::new(&data, &cf).set_first();
}

Not storing unparsed by value in Everything should make the structure not self-referential. Maybe you can store a reference to the unparsed string together with an index that indicates where the current position is in the parsing process in Everything?

2 Likes

why do you return the unparsed part as owned String? you can simply return it as borrowed &str.

playground

forget to mention, if you don't need to give access to unparsed, the Everything doesn't need to use multiple lifetimes.

2 Likes

That was my attempt to make it kind of lazy since I could call set_first immediately and set_second later or never.

Thank you. That's how the actual code works. I'll try to add 'a to the unparsed value!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.