Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In tman, the serialization and de-serialization of manifest.json/property.json should maintain their order. #122

Open
halajohn opened this issue Oct 13, 2024 · 4 comments
Labels
enhancement New feature or request tman

Comments

@halajohn
Copy link
Member

halajohn commented Oct 13, 2024

A compile switch is needed to quickly toggle between preserving the original order of code and not preserving it. In the tman scenario, the original order needs to be maintained, but in the runtime scenario, it's unnecessary. Preserving the original order might increase overhead in performance, disk size, or memory, so a switch may be required in the future.

@halajohn halajohn added the enhancement New feature or request label Oct 13, 2024
@halajohn halajohn added this to Kanban Oct 13, 2024
@halajohn halajohn moved this to Todo in Kanban Oct 13, 2024
@halajohn halajohn added the tman label Oct 15, 2024
@leoadonia
Copy link
Collaborator

leoadonia commented Oct 31, 2024

如果要实现按序保存, 那就需要能够识别出文件中的 fields 顺序, 即需要在 deserialize 中支持这个能力.

  • 目前 rust 中 serde lib 只是定义了 serialize 和 deserialize 接口, 并没有定义统一的 Value 模型. 现在 tman 中使用的 serde_json::Value 只是 json 实现库中定义的. 不同的文件格式对应的 serde 实现库中, 都有各自定义的 Value 模型. 比如:

    • json

      pub enum Value {
          Bool(bool),
          Number(Number),
          String(String),
          Array(Vec<Value>),
          Object(Map<String, Value>),
      }
    • yaml

      pub enum Value {
          Null,
          Bool(bool),
          Number(Number),
          String(String),
          Sequence(Sequence),
          Mapping(Mapping),
          Tagged(Box<TaggedValue>),
      }
      • msgpack

        pub enum Value {
            Nil,
            Boolean(bool),
            Integer(Integer),
            F32(f32),
            F64(f64),
            String(Utf8String),
            Binary(Vec<u8>),
            Array(Vec<Value>),
            Map(Vec<(Value, Value)>),
            Ext(i8, Vec<u8>),
        }

    对于 serde, 是基于 rust data type 定义了数据类型, https://serde.rs/data-model.html#types.

  • 对于 deserialize 的过程, serde 开放的自定义 function 的触发逻辑是, 先将 str 反序列化成中间态的 Value 后, 再调用自定义的 function. 也就是, 比如 json, 如果需要知道 fields 在文件中的定义顺序, 就必须要保证经过 serde_json 内部的反序列化后, 形成的中间态的 serde_json::Value 中的内容也需要是保序的. 那 serde_json::Value::Object 中的 Map 就需要是基于 IndexMap 的, 需要在 serde_json 依赖中开启 features = ["preserve_order"], 只能通过 feature 的方式开启 IndexMap. 会导致当前 crate 内都会采用 IndexMap. 如果为了性能考量, 需要单独提供一个 crate, 开启 features = ["preserve_order"], 提供 deserialize json 的方法.

  • 而并不一定所有的库都具备这个能力, 如果不具备的话, 就需要实现对应文件类型的 deserialize 能力.

从使用场景上来看, 可能会经过如下步骤:

  • property.json 被加载反序列化成 Property 对象.

  • Property 对象被转化成另一种结构, 如 DevServerProperty 对象.

  • 然后序列化传输给 graph designer.

  • 在 graph designer 中可能会做增删改的动作, 尤其是对于数组对象, 如 connections, 原始内容可能如 ["A", "B", "C"], 在 graph designer 中用户可能会删除 "A", 然后再增加 "A". 那 connections 就变成了 ["B", "C", "A"]. 与原始内容的顺序就不同了, 这时需不需要重排?

  • 同样, 对于 数组的元素是 object 的情况, 如 predefined_graphs 数组, 最好的方式应该是按照以下原则:

    • predefined_graphs 数组中元素的顺序, 按照 name 字段做排序, 即以 name 维度与原始数据做匹配, 与原始内容的顺序保持一致.
    • 每一个graph的内容, 最好是根据 name 匹配后, 获取原始内容对应的 graph 的 fields order, 按照该顺序调整graph的内容.

这样会存在如下问题:

  • 可能会新增 graph, 即如果要保存的内容一部分是存在原始数据的, 一部分是新增的. 那存在的那部分 graph 会是一种字段顺序, 新增的就会是另一种, 取决于序列化时的实现. 导致同一类数据的格式可能会存在不一致的情况.
  • 可能会对原始存在的内容做新增的操作, 新增的部分是没有 field order 的参考的, 又只能按照默认的规则排序.
  • 让用户感官上觉得结构发生了变化的原因不单单是字段的顺序, 也可能是由其他的格式化风格造成的, 比如 indent, 大括号是放在行尾还是新的一行开头等.

同样, 在 ide 中也会存在 formatter 工具, 可能会与 tman dump 时的规则不同.

一方面是不能提供完备的字段顺序的保存方案, 反而会造成数据排序混乱; 另一方面, 可能会与用户开发环境的 formatter 规则不同, 导致在使用 dev server dump 后, 用户再手动 formatter 产生文件内容变更, 造成开发上的不便. 所以, 并不适合在dump时参考已有数据的顺序.

@leoadonia
Copy link
Collaborator

leoadonia commented Oct 31, 2024

从本质上将, 需要做的事情应该是 dump 后, 自动 formatter. 并且, formatter 的规则要与用户开发环境上的一致.

从 tman 角度, 逻辑上并不在意 fields 的顺序. 所以只需要让用户觉得是按照相同 formatter 产生的结果, 尤其是用户手动 formatter 不会产生新的变更.

  • serde_json 中 PrettyFormatter 只支持设置 indent. 而在 vscode 中, 如果采用 prettier, formatter规则会更丰富, 如:

    {
         "tabWidth": 4,
         "useTabs": false,
         "singleQuote": true,
         "trailingComma": "all"
     }

@leoadonia
Copy link
Collaborator

如果 property.json / manifest.json 支持 json5, 即包含 comments, 对于 vscode 是可以支持的, 设置 files.associationsjsonc.

目前 serde 中有对 json5 支持的实现库: https://github.com/callum-oakley/json5-rs/tree/master.

但在保存文件的场景下会存在问题, 因为 json5-rs 的实现中, 还是以 serde_json::Value 来保存数据的, 那这样 comments 信息应该是会丢失的.

@halajohn
Copy link
Member Author

halajohn commented Nov 3, 2024

  1. 不只 graph designer 有需要, 之后如果要做 automatic code gen, 也需要能够保留 json 中的 order, 因为 message 会变成 function, 而 message property 会变成 function 的参数, 所以会有需要 function 的参数顺序等于 json 中的顺序.
  2. 用户 IDE 如果有自己的 formatter, 那个不在我们的雷达范围内. 因为有 formatter 的话, 原始的 json 跟我们处理过后的 json 都会经过那个 formatter, 如果那个 formatter 只是做 {, }, indent 等的重新排列, 那我们保留顺序, 还是很有帮助; 如果我们不保留顺序, 用户还是会看的挺乱. 如果那个 formatter 除了做前面那些事情外, 也会做 json field 的重新排列顺序, 那旧的 json 跟我们处理过后的 json, 也都会经过一样规则的排序, 那就没差了. 所以用户有没有自己的 formatter 不在我们的考虑范围内. 可以假设用户没有.
  3. graph designer 的 UI 如何设计使得用户可以自己决定顺序, 那个应该就让 UI 自行决定. dev-server 这边需要做的事情是, 吐出跟 json file 内的 order 一样的 information 给 graph designer, 并且当收到 graph designer 传回来的 结果后, 按照收到的 order 原封不动的序列化到 json file 中. 至于 graph designer 的 UI 设计是不是可以让用户自己插一个之前删除过的字段到原本的 order 顺序, 那可以留待 UI 来解决.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request tman
Projects
Status: Todo
Development

No branches or pull requests

2 participants