Static lifetime encapsulate

Hello,

I'm a Rust beginner and I'm struggeling a little bit with the ownership especially with 'static of an external dependency. I'm using the crate for Prolog Swipl and this is my current code:

use pnet::datalink::NetworkInterface;
use swipl::context::{ActivatedEngine, Context};
use swipl::engine::EngineActivation;
use swipl::init::initialize_swipl;
use swipl::result::PrologError;
use swipl::{pred, term};

pub struct Engine<> {
    engine: EngineActivation<'static>,
}

impl Engine {
    /// constructor
    pub fn new() -> Self {
        let engine = initialize_swipl().unwrap();

        Self { engine }
    }

    pub fn add_interface(self, ip: NetworkInterface) -> Result<(), PrologError> {
        let context: Context<_> = self.engine.into();
        for i in ip.ips.clone() {
            let value = format!(
                "_{{interface: _{{name: \"{}\"}}, _{{ip: \"{}\"}}",
                ip.name, i
            );
            let term = context.term_from_string(&*value)?;
            tracing::info!("append interface term: {:?}", term);

            context.call_once(pred!(writeq / 1), [&term])?;
        }

        Ok(())
    }

    pub fn add_ip(self, ip: String) -> Result<(), PrologError> {
        let context: Context<_> = self.engine.into();
        let value = format!("_{{ip: \"{}\"}}", ip);
        let term = context.term_from_string(&*value)?;
        tracing::info!("append ip term: {:?}", term);

        context.call_once(pred!(writeq / 1), [&term])?;
        Ok(())
    }
}

I get into stuck, because the engine is a static lifetime but I would like to get a struct, which hides the Prolog engine.

I would like to do in my main program

use pnet::datalink;

[...]
let prolog = Engine::new()
let interfaces = datalink::interfaces();

interfaces
    .into_iter()
    .filter(|i| !i.is_loopback() && !i.is_multicast() && i.is_up() && i.is_running())
    .for_each(|i| add_interface(prolog, i).unwrap());

Is this the correct way to do it? How can I improve my code in a better way?
Thanks a lot

Without diving into the details of the referenced crates, you probably want your add_* methods to take a &mut self instead of self.

A method that takes self by value moves the struct and it cannot be used again (unless returned -> Self).
A method that takes &mut self can be called again, which appears to be your use case.

If you haven't yet, check out the Rust book chapter on ownership.

1 Like

Yes, I exactly try &mut self but in this case the 'static lifetime of the exteral dependency create an error "cannot move". I try Arc but I didn't get a solution. IMHO the external EngineActivation cannot move but must be movable in my case. So how can I reach my goal?

Thanks

Maybe just store the Context<'static, ActivatedEngine<'static>> directly in your struct?

use pnet::datalink::NetworkInterface;
use swipl::context::{ActivatedEngine, Context};
use swipl::engine::EngineActivation;
use swipl::init::initialize_swipl;
use swipl::result::PrologError;
use swipl::{pred, term};

pub struct Engine<> {
    engine: Context<'static, ActivatedEngine<'static>>,
}

impl Engine {
    /// constructor
    pub fn new() -> Self {
        let engine = initialize_swipl().unwrap().into();

        Self { engine }
    }

    pub fn add_interface(&mut self, ip: NetworkInterface) -> Result<(), PrologError> {
        for i in ip.ips.clone() {
            let value = format!(
                "_{{interface: _{{name: \"{}\"}}, _{{ip: \"{}\"}}",
                ip.name, i
            );
            let term = self.engine.term_from_string(&*value)?;
            tracing::info!("append interface term: {:?}", term);

            self.engine.call_once(pred!(writeq / 1), [&term])?;
        }

        Ok(())
    }

    pub fn add_ip(&mut self, ip: String) -> Result<(), PrologError> {
        let value = format!("_{{ip: \"{}\"}}", ip);
        let term = self.engine.term_from_string(&*value)?;
        tracing::info!("append ip term: {:?}", term);

        self.engine.call_once(pred!(writeq / 1), [&term])?;
        Ok(())
    }
}

(untested)

Oh great, 1000 times thanks a lot, this works and I understand it :slight_smile:

One question is it possible to make my struct cloneable

#[derive(Clone)]
pub struct Engine<>

but in this case the inner property Context<'static, ActivatedEngine<'static>> does not implement the clone-trait?

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.