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!