Implementing with Phantom data and without?

hey there, i would love avoiding code repetition on my data structure, :grinning:
actually my data structure is using specific implementation base on 3 different generic phantom data... but i would love implementing one method for all generic phantom data
is it possible to do that without repeating the method implementation 3 times on each phantom data implementation ?
what i want is fn get_access_type(&self) -> String implemented on all generic State ?

mod file_access {
    pub struct ReadOnly;
    pub struct WriteOnly;
    pub struct ReadWrite;

    pub enum AccesType {
        ReadOnly,
        WriteOnly,
        ReadWrite,
    }
    pub struct Data<State = ReadOnly> {
        data: String,
        pub access: AccesType,
        _ph_data: std::marker::PhantomData<State>,
    }

    impl Data {
        pub fn get_access_type(&self) -> String {
            match self.access {
                AccesType::ReadOnly => "ReadOnly".to_owned(),
                AccesType::WriteOnly => "WriteOnly".to_owned(),
                AccesType::ReadWrite => "ReadWriteOnly".to_owned(),
            }
        }
    }
    
    impl Data<ReadOnly> {
        pub fn new_read_only(input: &str) -> Self {
            Self {
                data: String::from(input),
                _ph_data: std::marker::PhantomData,
                access: AccesType::ReadOnly,
            }
        }

        pub fn read_data(&self) {
            print!("{}", self.data);
        }

        pub fn upgrade_right(&mut self) -> Data<ReadWrite> {
            Data {
                data: std::mem::take(&mut self.data),
                _ph_data: std::marker::PhantomData,
                access: AccesType::ReadWrite,
            }
        }
    }

    impl Data<WriteOnly> {
        pub fn new_write_only(input: &str) -> Self {
            Self {
                data: String::from(input),
                _ph_data: std::marker::PhantomData,
                access: AccesType::WriteOnly,
            }
        }
        pub fn write_data(&mut self, data_to_write: &str) {
            self.data.clear();
            self.data.push_str(data_to_write);
        }
        pub fn upgrade_right(&mut self) -> Data<ReadWrite> {
            Data {
                data: std::mem::take(&mut self.data),
                _ph_data: std::marker::PhantomData,
                access: AccesType::ReadWrite,
            }
        }
    }

    impl Data<ReadWrite> {
        pub fn new_read_and_write(input: &str) -> Self {
            Self {
                data: String::from(input),
                _ph_data: std::marker::PhantomData,
                access: AccesType::ReadWrite,
            }
        }
        pub fn read_data(&self) {
            print!("{}", self.data);
        }
        pub fn write_data(&mut self, data_to_write: &str) {
            self.data.clear();
            self.data.push_str(data_to_write);
        }
        pub fn downgrade_right(&mut self) -> Data<ReadOnly> {
            Data {
                data: std::mem::take(&mut self.data),
                _ph_data: std::marker::PhantomData,
                access: AccesType::ReadOnly,
            }
        }
    }
}

-    impl Data {
+    impl<T> Data<T> {
         pub fn get_access_type(&self) -> String {

Unlike lifetime parameters, elided type parameters in impl headers don't mean "introduce a new generic variable", they mean "use the default type" (or error if the type parameter doesn't have a default). So what you had was equivalent to

    impl Data<ReadOnly> {
1 Like

perfect, just what i need thanks you :wink: