Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9464168
  • 博文数量: 1750
  • 博客积分: 12961
  • 博客等级: 上将
  • 技术积分: 20091
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-09 11:25
个人简介

偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.

文章分类

全部博文(1750)

文章存档

2024年(26)

2023年(26)

2022年(112)

2021年(217)

2020年(157)

2019年(192)

2018年(81)

2017年(78)

2016年(70)

2015年(52)

2014年(40)

2013年(51)

2012年(85)

2011年(45)

2010年(231)

2009年(287)

分类: 其他平台

2024-09-09 14:09:09


  1. 参考 https://www.jianshu.com/p/f1110b22cb5c

编码方案, Cap'n Proto编码的数据格式跟在内存里面的布局是一致的,所以可以直接将编码好的structure直接字节存放到硬盘上面。


点击(此处)折叠或打开

  1. Cap'n Proto的编码是方案是独立于任何平台的,但在现在的CPU上面(小端序)会有更高的性能。数据的组织类似compiler组织struct:固定宽度,固定偏移,以及合适的内存对齐,对于可变的数组使用pointer嵌入,而pointer也是使用的偏移存放而不是绝对地址。整数使用的是小端序,因为多数现代CPU都是小端序的。

  2. 其实如果熟悉C或者C++的结构体,就可以知道Cap'n Proto的编码方式就跟struct的内存布局差不多。



点击(此处)折叠或打开

  1. 跟Protobuf一样,Cap'n Proto也需要定义描述文件,然后通过capnp的编译器编译成特定语言的对象使用.
  2. 示例 
  3. @0xdbb9ad1f14bf0b36; # unique file ID, generated by `capnp id`

  4. struct Person {
  5.   name @0 :Text;
  6.   birthdate @3 :Date;

  7.   email @1 :Text;
  8.   phones @2 :List(PhoneNumber);

  9.   struct PhoneNumber {
  10.     number @0 :Text;
  11.     type @1 :Type;

  12.     enum Type {
  13.       mobile @0;
  14.       home @1;
  15.       work @2;
  16.     }
  17.   }
  18. }

  19. struct Date {
  20.   year @0 :Int16;
  21.   month @1 :UInt8;
  22.   day @2 :UInt8;
  23. }

  24. 类型是定义在名字后面的,通常来说,对于一个变量来说,我们可能{BANNED}最佳关注的是它的名字,一个好的命名,就很容易让大家知道是干啥的。譬如上面的name一看就知道是表示的用户的名字。这点跟c语言是反的,它是先类型,在变量名,不过很多后续的语言,譬如go,rust等都是先名字,再类型了。
  25. @N用来给struct里面的field进行编号,编号从0开始,而且必须是连续的(这点跟Protobuf不一样)。上面birthdate虽然看起来在email和phones的前面,但是它的编号较大,实际编码的时候会放到后面。
语法

点击(此处)折叠或打开

  1. 使用 #进行注释,注释应该跟在定义的后面,或者新启一行:
  2. struct Date {
  3.   # A standard Gregorian calendar date.

  4.   year @0 :Int16;
  5.   # The year. Must include the century.
  6.   # Negative value indicates BC.

  7.   month @1 :UInt8; # Month number, 1-12.
  8.   day @2 :UInt8; # Day number, 1-30.
  9. }

  10. 内置类型
  11. Void: Void
  12. Boolean: Bool
  13. Integers: Int8, Int16, Int32, Int64
  14. Unsigned integers: UInt8, UInt16, UInt32, UInt64
  15. Floating-point: Float32, Float64
  16. Blobs: Text, Data
  17. Lists: List(T)

  18. Void只有一个可能的值,使用0 bits进行编码,通常很少使用,但是可以作为union的member。
  19. Text通常是UTF-8编码的,使用NULL结尾的字符串。
  20. Data是任意二进制数据。
  21. List是一个泛型类型,我们可以用特定类型去特化实现,譬如List(Int32)就是一个Int32的List

结构体其实类似于c的struct,field的有名字,有类型定义,同时需要编号:
struct Person { name @0 :Text; email @1 :Text; }

Field也可以有默认值:

foo @0 :Int32 = 123; bar @1 :Text = "blah"; baz @2 :List(Bool) = [ true, false, false, true ]; qux @3 :Person = (name = "Bob", email = "bob@example.com"); corge @4 :Void = void; grault @5 :Data = 0x"a1 40 33";


点击(此处)折叠或打开

  1. Union是定义在struct里面同一个位置的一组fields,一次只能允许一个field被设置,我们使用不一样的tag来获知当前哪个field被设置了,不同于c里面的union,它不是类型,只是简单的fields聚合。
  2. struct Person {
  3.   # ...

  4.   employment :union {
  5.     unemployed @4 :Void;
  6.     employer @5 :Company;
  7.     school @6 :School;
  8.     selfEmployed @7 :Void;
  9.     # We assume that a person is only one of these.
  10.   }
  11. }

  12. union可以没有名字,但是一个struct里面{BANNED}最佳多只能包含一个没名字的union:

  13. Union里面的field需要跟struct的field一起编号。
  14. 我们在上面的union中使用了Void类型,这个类型没有任何额外的信息,仅仅是为了跟其他状态区分。
  15. 通常,当一个struct初始化的时候,在union里面具有{BANNED}最佳小number field会被默认的设置,如果不想默认设置任何field,我们可以用在union里面的{BANNED}最佳小number定义一个unset的field。
  16. 我们可以将当前存在的field加入一个新的union,并且不会破坏当前数据的兼容性。


  17. group将一组fields封装到特定的作用域里面:

  18. struct Person {
  19.   # ...

  20.   # Note: This is a terrible way to use groups, and meant
  21.   # only to demonstrate the syntax.
  22.   address :group {
  23.     houseNumber @8 :UInt32;
  24.     street @9 :Text;
  25.     city @10 :Text;
  26.     country @11 :Text;
  27.   }
  28. }

  29. group 里面的fields仍然是struct的fields,需要跟其他struct的fields一起编号。

  30. group 的用法一般用在 union 里边,用于后期扩展.

点击(此处)折叠或打开

  1. 动态类型域
  2. Struct可以定义field的类型为AnyPointer,类似于c里面的void*.

  3. 枚举
  4. Enum就是一组符号值的集合:
  5. enum Rfc3092Variable {
  6.   foo @0;
  7.   bar @1;
  8.   baz @2;
  9.   qux @3;
  10.   # ...
  11. }

  12. Enum的成员必须从0开始编号,在c语言里面,enum通常都是数字类型的,但是在Cap'n Proto里面,它还可以是其他值



  13. Interface是一组methods的集合,各个method可以有参数,有返回值,methods也必须从0开始编号。Interface支持继承,同样也支持多继承

  14. interface Node {
  15.   isDirectory @0 () -> (result :Bool);
  16. }

  17. interface Directory extends(Node) {
  18.   list @0 () -> (list: List(Entry));
  19.   struct Entry {
  20.     name @0 :Text;
  21.     node @1 :Node;
  22.   }

  23.   create @1 (name :Text) -> (file :File);
  24.   mkdir @2 (name :Text) -> (directory :Directory);
  25.   open @3 (name :Text) -> (node :Node);
  26.   delete @4 (name :Text);
  27.   link @5 (name :Text, node :Node);
  28. }

  29. interface File extends(Node) {
  30.   size @0 () -> (size: UInt64);
  31.   read @1 (startAt :UInt64 = 0, amount :UInt64 = 0xffffffffffffffff)
  32.        -> (data: Data);
  33.   # Default params = read entire file.

  34.   write @2 (startAt :UInt64, data :Data);
  35.   truncate @3 (size :UInt64);
  36. }

  37. 泛型
  38. 我们可以定义泛型的struct或者interface
  39. struct Map(Key, Value) {
  40.   entries @0 :List(Entry);
  41.   struct Entry {
  42.     key @0 :Key;
  43.     value @1 :Value;
  44.   }
  45. }

  46. struct People {
  47.   byName @0 :Map(Text, Person);
  48.   # Maps names to Person instances.
  49. }
  50. 定义了一个泛型的Map,然后在People里面用Text,Person作为参数来特化这个Map,如果我们了解c++的模板,就可以知道他们差不多。


  51. 泛型方法
  52. interface也可以提供泛型method:
  53. interface Assignable(T) {
  54.   # A generic interface, with non-generic methods.
  55.   get @0 () -> (value :T);
  56.   set @1 (value :T) -> ();
  57. }

  58. interface AssignableFactory {
  59.   newAssignable @0 [T] (initialValue :T)
  60.       -> (assignable :Assignable(T));
  61.   # A generic method.
  62. }
  63. 定义了一个泛型的interface,然后在对应的factory里面,创建这个interface的method就是泛型的method。


  64. const来定义常量
  65. const pi :Float32 = 3.14159;
  66. const bob :Person = (name = "Bob", email = "bob@example.com");
  67. const secret :Data = 0x"9f98739c2b53835e 6720a00907abd42f";

  68. const foo :Int32 = 123;
  69. const bar :Text = "Hello";
  70. const baz :SomeStruct = (id = .foo, message = .bar);

  71. 通常常量都都定义在全局scope里面,我们通过.来进行引用获取


  72. 嵌套,作用域以及别名
  73. 我们可以在struct或者interface里面嵌套常量,别名或者新的类型定义。

  74. struct Foo {
  75.   struct Bar {
  76.     #...
  77.   }
  78.   bar @0 :Bar;
  79. }

  80. struct Baz {
  81.   bar @0 :Foo.Bar;
  82. }

  83. struct Qux {
  84.   using Foo.Bar;
  85.   bar @0 :Bar;
  86. }

  87. struct Corge {
  88.   using T = Foo.Bar;
  89.   bar @0 :T;
  90. }


  91. import导入其他文件的类型定义
  92. struct Foo {
  93.   # Use type "Baz" defined in bar.capnp.
  94.   baz @0 :import "bar.capnp".Baz;
  95. }

  96. 也可以直接使用using来设置别名
  97. using Bar = import "bar.capnp";

  98. struct Foo {
  99.   # Use type "Baz" defined in bar.capnp.
  100.   baz @0 :Bar.Baz;
  101. }
  102. using import "bar.capnp".Baz;

  103. struct Foo {
  104.   baz @0 :Baz;
  105. }


  106. 唯一ID
  107. 每个Cap'n Proto文件都必须有唯一的一个64bit ID,使用capnp id生成。譬如{BANNED}最佳开始例子里面的file ID
  108. # file ID
  109. @0xdbb9ad1f14bf0b36














阅读(133) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~