Есть ли безопасный, эргономичный c способ изменить фантомный тип в сложной структуре? - PullRequest
1 голос
/ 17 февраля 2020

Предположим, мы определили обобщенную c структуру со многими полями, представляющими типобезопасный конечный автомат с использованием фантомного типа:

struct Foo<State> {
    a: A,
    b: B,
    c: C,
    //...
    state: PhantomData<State>,
}

Затем мы можем написать типобезопасный переход состояния:

impl Foo<SourceState> {
    fn transition(self, extra: X) -> Foo<DestinationState> {
        let Foo {a, b, c, state: _} = self;
        // do lots of stuff
        Foo { a, b, c, state: PhantomData } 
    }
}

Но нам нужно неловко распаковать каждое поле и упаковать в другую структуру.

Мы также могли бы использовать mem::transmute, хотя я понимаю, что разные мономорфизации одного и того же У struct не гарантируется одинаковая структура памяти.

Я надеялся, что Foo { state: PhantomData, ..self } сработает; увы, он не компилируется.

Есть ли какой-нибудь канонический, эргономический c, безопасный способ написать это?

1 Ответ

2 голосов
/ 17 февраля 2020

Невозможно сделать это прямым способом, потому что они бывают двух разных типов: в этом-то и весь смысл вашего кода. Чтобы упростить это, я бы сделал это в 2 шага, с обобщенным c переходом, являющимся вторым:

use core::marker::PhantomData;

struct Foo<State> {
    a: i32,
    b: i32,
    c: i32,
    //...
    state: PhantomData<State>,
}

struct SourceState;
struct DestinationState;

impl<Src> Foo<Src> {
    fn transition<Dest>(self) -> Foo<Dest> {
        let Foo {a, b, c, state: _} = self;

        Foo { a, b, c, state: PhantomData } 
    }
}

impl Foo<SourceState> {
    fn to_destination_state(mut self, extra: ()) -> Foo<DestinationState> {
        // Do whatever you want with self

        self.transition()
    }
}

В качестве альтернативы, вы можете абстрагировать тот факт, что у вас есть состояние:

mod stateful {
    use core::marker::PhantomData;

    pub struct Stateful<T, State> {
        pub data: T,
        state: PhantomData<State>,
    }

    impl<T, SrcState> Stateful<T, SrcState> {
        pub fn transform<DestState>(self) -> Stateful<T, DestState> {
            let Stateful { data, state: _ } = self;

            Stateful {
                data,
                state: Default::default(),
            }
        }
    }
}

struct Data {
    a: i32,
    b: i32,
    c: i32,
}

struct SourceState;
struct DestinationState;

type Foo<State> = stateful::Stateful<Data, State>;

impl Foo<SourceState> {
    fn to_destination_state(mut self, extra: ()) -> Foo<DestinationState> {
        // Do whatever you want with self.data

        self.transform()
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...