diff --git a/kernel/kernel/include/model/Model.hpp b/kernel/kernel/include/model/Model.hpp index 3fe94fb..933fd18 100644 --- a/kernel/kernel/include/model/Model.hpp +++ b/kernel/kernel/include/model/Model.hpp @@ -58,28 +58,22 @@ struct Model_Private_Access_Root { template struct Model_Private_Base; -template -struct Model_Private_Handle { - explicit Model_Private_Handle(Model_Instance* value) noexcept; - decltype(auto) operator*() const noexcept; - auto operator->() const noexcept; - template - void bind() noexcept; - private: - Model_Instance* instance{}; /* 非拥有借用;指向外层 Model 的 Root 子对象。 */ - void* (* private_view)(void*){}; /* 将唯一实际 Private 调整为当前 Def 层的 Private 视图。 */ -}; +template typename Endpoint::Private& model_private(Endpoint& model) noexcept; +template const typename Endpoint::Private& model_private(const Endpoint& model) noexcept; +template inline constexpr unsigned char Model_Private_Type_Token{}; template struct Model_Private_Pointer { - using element_type = std::remove_reference_t()->d)>; + using element_type = std::remove_reference_t()))>; decltype(auto) operator*() const noexcept; Model_Pointer model; /* 裸指针为借用;智能指针按自身类型拥有 Model。 */ }; -struct Model_State_Deleter { - void operator()(void* value) const noexcept; - void (*destroy)(void*){}; /* 与被擦除的实际 endpoint state 匹配。 */ +/* Root 的唯一类型擦除 state 同时携带销毁和 Private 基类调整入口。 */ +struct Model_State_Operations { + void operator()(void* value) const noexcept; + void (*destroy)(void*) noexcept {}; /* 与被擦除的实际 endpoint state 匹配。 */ + void* (*resolve_private)(void*, const void*) noexcept {}; /* 将 Root 唯一 state 调整为请求层的 Private。 */ }; struct Model_Instance { @@ -90,30 +84,30 @@ struct Model_Instance { Model_Instance(Model_Instance&&) = delete; Model_Instance& operator=(Model_Instance&&) = delete; protected: - [[nodiscard]] bool initialized() const noexcept; + [[nodiscard]] bool initialized() const noexcept; private: - template - friend struct Model_Private_Handle; - template - friend struct Model_Private_Base; - template - friend struct Model_Builder_Instance; - template - void initialize_endpoint(Args&&... args); - template - Model_State& state() noexcept; - std::unique_ptr state_owner; /* 唯一拥有实际 Private 与完整附件集合。 */ + template + friend struct Model_Private_Base; + template + friend struct Model_Builder_Instance; + template friend typename Endpoint::Private& model_private(Endpoint& model) noexcept; + template friend const typename Endpoint::Private& model_private(const Endpoint& model) noexcept; + template + void initialize_endpoint(Args&&... args); + template + Model_State& state() noexcept; + std::unique_ptr state_owner; /* 唯一拥有实际 Private、附件及类型操作。 */ }; template struct Model_Builder_Instance { protected: - template - void initialize_model(Args&&... args); - Self& model(); - std::unique_ptr release_model(); + template + void initialize_model(Args&&... args); + Self& model(); + std::unique_ptr release_model(); private: - std::unique_ptr model_owner; /* 构建期唯一拥有尚未发布的最终 Model。 */ + std::unique_ptr model_owner; /* 构建期唯一拥有尚未发布的最终 Model。 */ }; } // namespace detail struct Prop_Tag { @@ -132,32 +126,31 @@ struct Root : detail::Model_Instance { struct Private {}; protected: - Root() = default; - ~Root() = default; + Root() = default; + ~Root() = default; }; -/* 业务定义直接使用 Prev、Prev_Private、Builder 和 d;其余别名只供框架递归。 */ +/* 业务定义直接使用 Prev、Prev_Private 和 Builder;其余别名只供框架递归。 */ template struct Def : detail::Model_Definition::Public_Base { private: - using Definition = detail::Model_Definition; + using Definition = detail::Model_Definition; public: - using Model_Layers = typename detail::Merge_Model_Type_Lists>::Type; - using Model_Registrations = typename Definition::Registration_List; - template - using Prev = detail::Model_Value; - using Prev_Private = typename Definition::Private_Base; + using Model_Layers = typename detail::Merge_Model_Type_Lists>::Type; + using Model_Registrations = typename Definition::Registration_List; + template + using Prev = detail::Model_Value; + using Prev_Private = typename Definition::Private_Base; - struct Builder : Definition::Builder_Base { - Builder() = default; - template - explicit Builder(First&& first, Rest&&... rest); - std::unique_ptr build(); - }; + struct Builder : Definition::Builder_Base { + Builder() = default; + template + explicit Builder(First&& first, Rest&&... rest); + std::unique_ptr build(); + }; - Def(); - [[nodiscard]] bool model_initialized() const noexcept; - detail::Model_Private_Handle d; /* 非拥有类型化视图;状态始终由公共 Root 唯一拥有。 */ + Def() = default; + [[nodiscard]] bool model_initialized() const noexcept; }; /* proxy 的指针种类决定 Model 生命周期;facade 始终只看最终 Private。 */ diff --git a/kernel/kernel/include/model/Model.ipp b/kernel/kernel/include/model/Model.ipp index eadd8a4..fd0b5f7 100644 --- a/kernel/kernel/include/model/Model.ipp +++ b/kernel/kernel/include/model/Model.ipp @@ -127,13 +127,26 @@ struct Model_State : Endpoint_Attachments -void bind_model_handles(Active_Endpoint& model, Model_Type_List) noexcept { - ((static_cast(model).d.template bind()), ...); +void* resolve_model_private(void* state, const void* token, Model_Type_List) noexcept { + auto& private_data = static_cast*>(state)->private_data; + void* result{}; + ((token == &Model_Private_Type_Token ? result = static_cast(std::addressof(private_data)) : nullptr), ...); + return result; } -inline Model_Instance::Model_Instance() : state_owner(nullptr, Model_State_Deleter{}) {} +template +void destroy_model_state(void* state) noexcept { + delete static_cast*>(state); +} + +template +void* resolve_model_state_private(void* state, const void* token) noexcept { + return resolve_model_private(state, token, typename Endpoint::Model_Layers{}); +} + +inline Model_Instance::Model_Instance() : state_owner(nullptr, Model_State_Operations{}) {} inline Model_Instance::~Model_Instance() = default; @@ -141,7 +154,7 @@ inline bool Model_Instance::initialized() const noexcept { return static_cast(state_owner); } -inline void Model_State_Deleter::operator()(void* value) const noexcept { +inline void Model_State_Operations::operator()(void* value) const noexcept { if (destroy) destroy(value); } @@ -165,10 +178,7 @@ template void Model_Instance::initialize_endpoint(Args&&... args) { auto state = std::make_unique>(std::forward(args)...); static_cast(state->private_data).instance = this; - state_owner = std::unique_ptr{state.release(), Model_State_Deleter{[](void* value) { - delete static_cast*>(value); - }}}; - bind_model_handles(static_cast(*this), typename Endpoint::Model_Layers{}); + state_owner = std::unique_ptr{state.release(), Model_State_Operations{destroy_model_state, resolve_model_state_private}}; } template @@ -177,30 +187,20 @@ Model_State& Model_Instance::state() noexcept { } template -Model_Private_Handle::Model_Private_Handle(Model_Instance* value) noexcept : instance(value) {} - -template -template -void Model_Private_Handle::bind() noexcept { - private_view = [](void* state) -> void* { - auto& private_data = static_cast*>(state)->private_data; - return static_cast(std::addressof(private_data)); - }; +typename Endpoint::Private& model_private(Endpoint& model) noexcept { + auto& instance = static_cast(model); + return *static_cast(instance.state_owner.get_deleter().resolve_private(instance.state_owner.get(), &Model_Private_Type_Token)); } template -decltype(auto) Model_Private_Handle::operator*() const noexcept { - return *static_cast(private_view(instance->state_owner.get())); -} - -template -auto Model_Private_Handle::operator->() const noexcept { - return std::addressof(operator*()); +const typename Endpoint::Private& model_private(const Endpoint& model) noexcept { + const auto& instance = static_cast(model); + return *static_cast(instance.state_owner.get_deleter().resolve_private(instance.state_owner.get(), &Model_Private_Type_Token)); } template decltype(auto) Model_Private_Pointer::operator*() const noexcept { - return *model->d; + return model_private(*model); } template @@ -226,9 +226,6 @@ std::unique_ptr Model_Builder_Instance::release_model() { } } // namespace aethera::detail namespace aethera { -template -Def::Def() : d{static_cast(this)} {} - template template Def::Builder::Builder(First&& first, Rest&&... rest) { diff --git a/kernel/kernel/include/model/design.md b/kernel/kernel/include/model/design.md index 21722ca..dda1f76 100644 --- a/kernel/kernel/include/model/design.md +++ b/kernel/kernel/include/model/design.md @@ -24,8 +24,9 @@ Builder 在构建具体 endpoint 时,才由公共 `Root` 一次物化该 endpo 的待发布对象是私有唯一所有权,只能通过 `build()` 移出。被继承的定义层只贡献注册、值类型和 Private 基类,不创建自己的状态。相同 Tag 重复注册属于编译期错误。 -每层 `d` 都是对 Root 唯一状态的非拥有类型化视图。最终层 `d` 返回最终 Private;模型转换为某个基类后,该基类的 `d` 返回同一最终 -Private 对象中的对应基类子对象。Model 实体必须通过 Builder 或 Model proxy 工厂物化;普通构造只建立定义对象,不产生运行状态。 +Root 的类型擦除 state 操作表只保存一份 Private 解析器,Def 层不再保存 `d` 指针。框架内部通过零状态 +`model_private(model)` 按模型的静态层选择类型化视图;模型转换为某个基类后,仍返回同一最终 Private 对象中的对应基类子对象。Model +实体必须通过 Builder 或 Model proxy 工厂物化;普通构造只建立定义对象,不产生运行状态。 跨模块 facade 直接声明消费方需要的 Private 能力。`make_model_proxy`、`make_model_proxy_shared` 与 `model_proxy_view` 分别承载独占、共享和非拥有生命周期,同时把 proxy 解引用目标映射到 Model 的唯一 Private;实体公开类不实现 facade 值转发。 diff --git a/kernel/kernel/include/model/registration/Concurrent_Registration.ipp b/kernel/kernel/include/model/registration/Concurrent_Registration.ipp index 1049831..ef71365 100644 --- a/kernel/kernel/include/model/registration/Concurrent_Registration.ipp +++ b/kernel/kernel/include/model/registration/Concurrent_Registration.ipp @@ -17,19 +17,19 @@ void initialize_concurrent_value(Value& target, T&& value) { template template requires Settable_Concurrent Endpoint& Concurrent_Model_API::set(Args&&... args) { auto& self = static_cast(*this); - self.d->template concurrent().set(std::forward(args)...); + model_private(self).template concurrent().set(std::forward(args)...); return self; } template template requires Gettable_Concurrent const Endpoint& Concurrent_Model_API::get(Args&&... args) const { const auto& self = static_cast(*this); - self.d->template concurrent().get(std::forward(args)...); + model_private(self).template concurrent().get(std::forward(args)...); return self; } template template requires Builder_Settable_Concurrent typename Endpoint::Builder& Concurrent_Builder_API::set(Args&&... args) { auto& builder = static_cast(*this); - auto& concurrent = this->model().d->template concurrent(); + auto& concurrent = model_private(this->model()).template concurrent(); concurrent.internal.builder_set([&](auto& value) { initialize_concurrent_value(value, std::forward(args)...); }); diff --git a/kernel/kernel/include/model/registration/Relation_Registration.ipp b/kernel/kernel/include/model/registration/Relation_Registration.ipp index a526ae1..6ee4bc4 100644 --- a/kernel/kernel/include/model/registration/Relation_Registration.ipp +++ b/kernel/kernel/include/model/registration/Relation_Registration.ipp @@ -3,13 +3,13 @@ namespace aethera::detail { template template requires Editable_Relation Endpoint& Relation_Model_API::edit(Args&&... args) { auto& self = static_cast(*this); - self.d->template relation_attachment().edit(std::forward(args)...); + model_private(self).template relation_attachment().edit(std::forward(args)...); return self; } template template requires Buildable_Relation typename Endpoint::Builder& Relation_Builder_API::relation(Fn&& fn) { auto& builder = static_cast(*this); - this->model().d->template relation_attachment().internal.build(std::forward(fn)); + model_private(this->model()).template relation_attachment().internal.build(std::forward(fn)); return builder; } template template requires Relation_Model_Tag diff --git a/kernel/kernel/module/frame_policy/src/Throttled_Latest_Only.cpp b/kernel/kernel/module/frame_policy/src/Throttled_Latest_Only.cpp index 6371325..05fc761 100644 --- a/kernel/kernel/module/frame_policy/src/Throttled_Latest_Only.cpp +++ b/kernel/kernel/module/frame_policy/src/Throttled_Latest_Only.cpp @@ -13,15 +13,15 @@ auto positive_duration(std::chrono::steady_clock::duration duration) noexcept -> Throttled_Latest_only::Throttled_Latest_only() = default; Throttled_Latest_only::~Throttled_Latest_only() noexcept { if (!model_initialized()) return; - if (!d->destructible()) { + if (!detail::model_private(*this).destructible()) { std::terminate(); } } auto Throttled_Latest_only::start() -> std::expected { - return d->start(); + return detail::model_private(*this).start(); } auto Throttled_Latest_only::stop(Stop_Completion completion) -> std::expected { - return d->stop(std::move(completion)); + return detail::model_private(*this).stop(std::move(completion)); } Throttled_Latest_only::Private::Private(proxy timer_service, proxy scene, proxy sink) : timer_service(std::move(timer_service)), scene(std::move(scene)), sink(std::move(sink)) {} auto Throttled_Latest_only::Private::start() -> std::expected { diff --git a/kernel/kernel/module/scene/test/Scene_Tests.cpp b/kernel/kernel/module/scene/test/Scene_Tests.cpp index 72b3992..821d09b 100644 --- a/kernel/kernel/module/scene/test/Scene_Tests.cpp +++ b/kernel/kernel/module/scene/test/Scene_Tests.cpp @@ -39,11 +39,12 @@ TEST(Scene, Advances_Renderables_And_Composes_Task_Graph_In_Dag_Order) { auto graph = builder.build(); ASSERT_TRUE(graph.has_value()); auto scene = aethera::Scene::Builder{}.build(); - EXPECT_TRUE(scene->d->create_frame()); + auto& scene_private = aethera::detail::model_private(*scene); + EXPECT_TRUE(scene_private.create_frame()); scene->edit(std::move(*graph)); - EXPECT_TRUE(scene->d->advance().has_value()); + EXPECT_TRUE(scene_private.advance().has_value()); EXPECT_EQ(*advance_order, (std::vector{1, 2, 3})); - EXPECT_FALSE(scene->d->taskflow()->empty()); + EXPECT_FALSE(scene_private.taskflow()->empty()); advance_order->clear(); std::optional edit_error; scene->edit([](aethera::Dag_Relation::Editor& editor) { @@ -51,7 +52,7 @@ TEST(Scene, Advances_Renderables_And_Composes_Task_Graph_In_Dag_Order) { }, [&](std::expected result) { if (!result) edit_error = result.error(); }); - EXPECT_TRUE(scene->d->advance().has_value()); + EXPECT_TRUE(scene_private.advance().has_value()); ASSERT_TRUE(edit_error.has_value()); EXPECT_EQ(*edit_error, aethera::Dag_Result::node_not_found); EXPECT_EQ(*advance_order, (std::vector{1, 2, 3})); @@ -76,7 +77,8 @@ TEST(Scene, Owned_Dag_Rolls_Back_The_Whole_Invalid_Edit) { ASSERT_TRUE(graph.has_value()); auto scene = aethera::Scene::Builder{}.build(); scene->edit(std::move(*graph)); - ASSERT_TRUE(scene->d->advance().has_value()); + auto& scene_private = aethera::detail::model_private(*scene); + ASSERT_TRUE(scene_private.advance().has_value()); advance_order->clear(); std::optional edit_error; scene->edit([advance_order](aethera::Dag_Relation::Editor& editor) { @@ -85,26 +87,27 @@ TEST(Scene, Owned_Dag_Rolls_Back_The_Whole_Invalid_Edit) { }, [&](std::expected result) { if (!result) edit_error = result.error(); }); - ASSERT_TRUE(scene->d->advance().has_value()); + ASSERT_TRUE(scene_private.advance().has_value()); ASSERT_TRUE(edit_error.has_value()); EXPECT_EQ(*edit_error, aethera::Dag_Result::node_not_found); EXPECT_EQ(*advance_order, (std::vector{1})); } TEST(Scene, Render_Returns_Known_Submission_Result) { auto scene = aethera::Scene::Builder{}.build(); - auto frame = scene->d->create_frame(); + auto& scene_private = aethera::detail::model_private(*scene); + auto frame = scene_private.create_frame(); bool completed{}; - const auto unavailable_runtime = scene->d->render(frame, [&](aethera::proxy&, std::exception_ptr) { + const auto unavailable_runtime = scene_private.render(frame, [&](aethera::proxy&, std::exception_ptr) { completed = true; }); ASSERT_FALSE(unavailable_runtime); EXPECT_EQ(std::get(unavailable_runtime.error()), aethera::Run_Taskflow_Result::runtime_not_initialized); EXPECT_FALSE(completed); aethera::proxy empty_frame; - const auto missing_frame = scene->d->render(empty_frame, [&](aethera::proxy&, std::exception_ptr) {}); + const auto missing_frame = scene_private.render(empty_frame, [&](aethera::proxy&, std::exception_ptr) {}); ASSERT_FALSE(missing_frame); EXPECT_EQ(std::get(missing_frame.error()), aethera::scene::Render_State_Result::frame_missing); - const auto missing_completion = scene->d->render(frame, {}); + const auto missing_completion = scene_private.render(frame, {}); ASSERT_FALSE(missing_completion); EXPECT_EQ(std::get(missing_completion.error()), aethera::scene::Render_State_Result::completion_missing); } @@ -117,8 +120,9 @@ TEST(Scene, Rejects_The_Same_Renderable_Task_Graph_Twice) { ASSERT_TRUE(graph.has_value()); auto scene = aethera::Scene::Builder{}.build(); scene->edit(std::move(*graph)); - auto frame = scene->d->create_frame(); - const auto rendered = scene->d->render(frame, [](aethera::proxy&, std::exception_ptr) {}); + auto& scene_private = aethera::detail::model_private(*scene); + auto frame = scene_private.create_frame(); + const auto rendered = scene_private.render(frame, [](aethera::proxy&, std::exception_ptr) {}); ASSERT_FALSE(rendered); EXPECT_EQ(std::get(rendered.error()), aethera::Compose_Task_Graph_Result::already_composed); } diff --git a/kernel/kernel/test/model/Model_Tests.cpp b/kernel/kernel/test/model/Model_Tests.cpp index 8a3c621..da12f69 100644 --- a/kernel/kernel/test/model/Model_Tests.cpp +++ b/kernel/kernel/test/model/Model_Tests.cpp @@ -92,6 +92,8 @@ template concept Exposes_Relation_Model_API = requires(Model& model) { model.template edit(0); }; template concept Exposes_Relation_Builder_API = requires(Builder& builder) { builder.template relation([](auto&) {}); }; +template +concept Stores_Per_Layer_Private_Handle = requires(Model& model) { model.d; }; static_assert(std::derived_from); static_assert(std::derived_from); static_assert(std::derived_from); @@ -110,6 +112,9 @@ static_assert(aethera::detail::Builder_Settable_Concurrent); static_assert(!Exposes_Relation_Model_API); static_assert(!Exposes_Relation_Builder_API); +static_assert(!Stores_Per_Layer_Private_Handle); +static_assert(!Stores_Per_Layer_Private_Handle); +static_assert(!Stores_Per_Layer_Private_Handle); static_assert(pro::proxiable, Test_Model_Private_Facade>); static_assert(pro::proxiable, Other_Test_Model_Private_Facade>); TEST(Model, Every_Def_Layer_Can_Materialize_Its_Own_Endpoint) { @@ -122,7 +127,7 @@ TEST(Model, Every_Def_Layer_Can_Materialize_Its_Own_Endpoint) { auto model = builder.build(); EXPECT_EQ(test_model_base_private_instances, base_instances_before + 1); EXPECT_EQ(test_model_middle_private_instances, middle_instances_before); - EXPECT_EQ(model->d->concurrent().internal.use()->base_number, 3); + EXPECT_EQ(aethera::detail::model_private(*model).concurrent().internal.use()->base_number, 3); } EXPECT_EQ(test_model_base_private_instances, base_instances_before); { @@ -133,8 +138,8 @@ TEST(Model, Every_Def_Layer_Can_Materialize_Its_Own_Endpoint) { auto model = builder.build(); EXPECT_EQ(test_model_base_private_instances, base_instances_before + 1); EXPECT_EQ(test_model_middle_private_instances, middle_instances_before + 1); - EXPECT_EQ(model->d->concurrent().internal.use()->base_number, 5); - EXPECT_EQ(model->d->concurrent().internal.use()->middle_number, 7); + EXPECT_EQ(aethera::detail::model_private(*model).concurrent().internal.use()->base_number, 5); + EXPECT_EQ(aethera::detail::model_private(*model).concurrent().internal.use()->middle_number, 7); } EXPECT_EQ(test_model_base_private_instances, base_instances_before); EXPECT_EQ(test_model_middle_private_instances, middle_instances_before); @@ -163,7 +168,7 @@ TEST(Model, Registered_Value_Types_Build_Independent_Storages) { }); EXPECT_EQ(struct_initializer_calls, 1); auto model = builder.build(); - auto& properties = model->d->concurrent(); + auto& properties = aethera::detail::model_private(*model).concurrent(); EXPECT_EQ(properties.internal.internal_read.base_number, 2); EXPECT_EQ(properties.internal.internal_read.middle_number, 3); EXPECT_EQ(properties.internal.internal_read.number, 5); @@ -173,9 +178,9 @@ TEST(Model, Registered_Value_Types_Build_Independent_Storages) { EXPECT_EQ(state.middle_state, 19); EXPECT_EQ(state.state, 23); }); - auto& numbers = model->d->concurrent(); + auto& numbers = aethera::detail::model_private(*model).concurrent(); EXPECT_EQ(*numbers.internal.use(), (std::vector{11, 13})); - auto& other_numbers = model->d->concurrent(); + auto& other_numbers = aethera::detail::model_private(*model).concurrent(); EXPECT_EQ(*other_numbers.internal.use(), (std::vector{17, 19})); model->set([](Test_Model::Numbers& values) { values.assign({17, 19}); @@ -194,10 +199,11 @@ TEST(Model, Every_Def_Layer_Shares_One_Private_And_Storage_Set) { EXPECT_EQ(test_model_private_instances, instances_before + 1); EXPECT_EQ(test_model_base_private_instances, base_instances_before + 1); EXPECT_EQ(test_model_middle_private_instances, middle_instances_before + 1); - EXPECT_EQ(std::addressof(*middle->d), std::addressof(static_cast(*model->d))); - EXPECT_EQ(std::addressof(*base->d), std::addressof(static_cast(*model->d))); - auto* properties = std::addressof(model->d->concurrent()); - EXPECT_EQ(properties, std::addressof(model->d->concurrent())); + auto& endpoint_private = aethera::detail::model_private(*model); + EXPECT_EQ(std::addressof(aethera::detail::model_private(*middle)), std::addressof(static_cast(endpoint_private))); + EXPECT_EQ(std::addressof(aethera::detail::model_private(*base)), std::addressof(static_cast(endpoint_private))); + auto* properties = std::addressof(endpoint_private.concurrent()); + EXPECT_EQ(properties, std::addressof(endpoint_private.concurrent())); } EXPECT_EQ(test_model_private_instances, instances_before); EXPECT_EQ(test_model_base_private_instances, base_instances_before); @@ -206,7 +212,7 @@ TEST(Model, Every_Def_Layer_Shares_One_Private_And_Storage_Set) { TEST(Model, Registered_Struct_Set_Publishes_To_The_Same_Attachment) { auto model = Test_Model::Builder{}.build(); model->set(&Test_Model::Prop::number, 13); - auto& properties = model->d->concurrent(); + auto& properties = aethera::detail::model_private(*model).concurrent(); properties.internal.advance(); EXPECT_EQ(properties.internal.use()->number, 13); } @@ -216,7 +222,7 @@ TEST(Model, Derived_Def_Registers_And_Uses_A_New_Concurrent) { .set(&Test_Model_Middle::Middle_Data::middle_number, 47) .set(&Test_Model::Middle_Data::final_number, 53); auto model = builder.build(); - auto& storage = model->d->concurrent(); + auto& storage = aethera::detail::model_private(*model).concurrent(); EXPECT_EQ(storage.internal.use()->middle_number, 47); EXPECT_EQ(storage.internal.use()->final_number, 53); model->set(&Test_Model_Middle::Middle_Data::middle_number, 59); @@ -230,12 +236,12 @@ TEST(Model, Same_Name_Properties_In_Base_And_Derived_Layers_Are_Set_Independentl .set(&Test_Model_Base::Prop::same_name, 29) .set(&Test_Model::Prop::same_name, 31); auto model = builder.build(); - const auto* properties = model->d->concurrent().internal.use(); + const auto* properties = aethera::detail::model_private(*model).concurrent().internal.use(); EXPECT_EQ(static_cast(*properties).same_name, 29); EXPECT_EQ(properties->same_name, 31); model->set(&Test_Model_Base::Prop::same_name, 37); model->set(&Test_Model::Prop::same_name, 41); - auto& storage = model->d->concurrent(); + auto& storage = aethera::detail::model_private(*model).concurrent(); storage.internal.advance(); properties = storage.internal.use(); EXPECT_EQ(static_cast(*properties).same_name, 37); diff --git a/kernel/kernel/test/model/attachment/dag/Dag_Relation_Tests.cpp b/kernel/kernel/test/model/attachment/dag/Dag_Relation_Tests.cpp index ff962aa..35cd3fc 100644 --- a/kernel/kernel/test/model/attachment/dag/Dag_Relation_Tests.cpp +++ b/kernel/kernel/test/model/attachment/dag/Dag_Relation_Tests.cpp @@ -33,12 +33,12 @@ TEST(Dag_Relation, Registration_Composes_Only_Relation_APIs) { std::optional> completion; model->edit([](auto& editor) { editor.remove({1}); }, [&](auto result) { completion.emplace(std::move(result)); }); EXPECT_FALSE(completion.has_value()); - model->d->commit(); + aethera::detail::model_private(*model).commit(); ASSERT_TRUE(completion.has_value()); ASSERT_FALSE(completion->has_value()); EXPECT_EQ(completion->error(), aethera::Dag_Result::node_not_found); std::size_t nodes{}; - model->d->relation().for_each_topological([&](auto, auto&) { ++nodes; }); + aethera::detail::model_private(*model).relation().for_each_topological([&](auto, auto&) { ++nodes; }); EXPECT_EQ(nodes, 0); } } // namespace diff --git a/kernel/使用规范.md b/kernel/使用规范.md index 3e1f4d9..f2ff16b 100644 --- a/kernel/使用规范.md +++ b/kernel/使用规范.md @@ -5,7 +5,7 @@ - 注册写在所属 `Def` 的模板参数上。并发结构使用 `Concurrent_Registration`,关系结构使用 `Relation_Registration`。 - 同一个注册组可以连续登记多个 Tag;相同 Tag 在完整继承链只能注册一次。 - 注册只描述协议、Tag 和具体附件的映射。完整注册链按 Builder 正在构建的最终 endpoint 求值,并由公共 `Root` 一次物化唯一的 `Private + Model_Attachment_Set`。 -- Builder 只拥有一个最终 endpoint 对象槽;被继承的 Def 层不得创建自己的 endpoint state、对象副本或附件。每层 `d` 只是同一 Root 状态的非拥有 Private 视图。 +- Builder 只拥有一个最终 endpoint 对象槽;被继承的 Def 层不得创建自己的 endpoint state、对象副本、附件或 Private 指针。Private 解析器只随 Root 的唯一类型擦除 state 保存一份,定义层通过零状态 `model_private(model)` 选择自身的类型化视图。 - Model 实体必须通过 `Builder`、`make_model_proxy` 或接收已完成 Builder 对象的 proxy 工厂物化;普通构造不创建运行状态。 - 新协议必须放入 `model/registration`,与 `Concurrent_Registration`、`Relation_Registration` 同级,并自行提供 concept、注册项和 Model/Builder/Private 三组 CRTP API。具体附件统一放入 `model/attachment`,禁止重新建立顶层 `concurrent`、`relation` 分类目录,也禁止在 `Model` 内增加协议分支。 - 最终 endpoint 只继承实际注册协议的 API;未注册关系结构的 Builder 和实体不得出现关系函数,未注册并发结构的类型不得出现并发函数。 diff --git a/render_2D/render_2D/module/scene/Render_Scene_2D.cpp b/render_2D/render_2D/module/scene/Render_Scene_2D.cpp index 7685d96..a612555 100644 --- a/render_2D/render_2D/module/scene/Render_Scene_2D.cpp +++ b/render_2D/render_2D/module/scene/Render_Scene_2D.cpp @@ -62,7 +62,7 @@ Render_Scene_2D_Result Render_Scene_2D::Private::render(Frame_2D* frame, Complet } Render_Scene_2D_Result Render_Scene_2D::render(Frame_2D* frame, Completion completion) { - return d->render(frame, std::move(completion)); + return aethera::detail::model_private(*this).render(frame, std::move(completion)); } void Render_Scene_2D::activate_view() { diff --git a/render_2D/tests/Model_Adaptation_Test.cpp b/render_2D/tests/Model_Adaptation_Test.cpp index 07f7e6b..a352a60 100644 --- a/render_2D/tests/Model_Adaptation_Test.cpp +++ b/render_2D/tests/Model_Adaptation_Test.cpp @@ -15,8 +15,9 @@ TEST(Render_2D_Model, Every_Def_Layer_Uses_The_Final_Private_Instance) { auto renderable = Test_Renderable_2D::Builder{}.build(); auto* renderable_2d_layer = static_cast(renderable.get()); auto* kernel_renderable_layer = static_cast(renderable.get()); - EXPECT_EQ(std::addressof(*renderable_2d_layer->d), std::addressof(static_cast(*renderable->d))); - EXPECT_EQ(std::addressof(*kernel_renderable_layer->d), std::addressof(static_cast(*renderable->d))); + auto& endpoint_private = aethera::detail::model_private(*renderable); + EXPECT_EQ(std::addressof(aethera::detail::model_private(*renderable_2d_layer)), std::addressof(static_cast(endpoint_private))); + EXPECT_EQ(std::addressof(aethera::detail::model_private(*kernel_renderable_layer)), std::addressof(static_cast(endpoint_private))); } TEST(Render_2D_Model, Scene_Endpoint_Publishes_Properties_And_Owned_Dag) { @@ -30,7 +31,7 @@ TEST(Render_2D_Model, Scene_Endpoint_Publishes_Properties_And_Owned_Dag) { .set(&aethera::render_2d::Render_Scene_2D::Prop::view_active, true) .relation([dag = std::move(*dag)](auto& relation) mutable { relation = std::move(dag); }); auto scene = scene_builder.build(); - auto& properties = scene->d->concurrent(); + auto& properties = aethera::detail::model_private(*scene).concurrent(); EXPECT_EQ(properties.internal.use()->viewport, (aethera::render_2d::Size{32, 24})); EXPECT_TRUE(properties.internal.use()->view_active); aethera::render_2d::Frame_2D frame({1, 0});