4.6 KiB
制約と default
constraint は、値が満たすべき範囲を表す。
Int
String
>= 1
<= 65535
/Hello! .*/
constraint は & で合成できる。
Port = Int & >= 1 & <= 65535;
NarrowedPort = Port & > 443;
合成結果は両辺を同時に満たす範囲になる。 両立しない constraint は conflict になる。
Int & String # conflict
> 10 & < 5 # conflict
Int & > 10 & < 11 # conflict: integer candidate does not exist
Primitive and comparison constraints
組み込みの primitive range は次の通りである。
String
Int
Float
Bool
異なる primitive type を & で合成すると conflict になる。
数値比較 constraint は上下限として合成され、空の範囲になる場合は conflict になる。
Int & >= 1 & <= 65535 & > 443
Int の比較 constraint は integer literal を使う。
Float の比較 constraint は integer または float literal を使える。
Unknown
Unknown はすべての Decodal value を含む最上位 range である。
検査を無効化して具体値の情報を消す Any ではなく、値の範囲がまだ絞られていないことを表す。
Int & Unknown # Int
42 as Unknown # 42
Unknown as Int # conflict
Unknown 自体は concrete value を持たないため materialize できない。
concrete value で絞り込むか default を指定する必要がある。
Unknown default {}
Regex constraints
regex literal は string constraint である。
Host = /^api-[0-9]+$/;
複数の regex constraint を合成した場合、concrete string はすべてに一致する必要がある。
String & /^a/ & /z$/
regex constraint 同士の交差は合成時には判定されない。 そのため、次の範囲は合成時には conflict にならず、concrete value の検証時に失敗する。
String & /^a$/ & /^b$/
Rust runtime では regex engine を regex feature で有効にする。
feature が無効な場合、regex constraint の concrete value 検証は unsupported feature diagnostic になる。
Array constraints
array constraint は [...T] と書き、すべての要素へ T を適用する。
要素 constraint は必須である。
Names = [...String];
PositiveInts = [...(Int & > 0)];
concrete array と合成した場合、各要素は T に対して as と同じ規則で絞り込まれる。
空 array は任意の array constraint を満たす。
要素 constraint が object range の場合、右辺にだけある field は abstract のまま各要素へ残る。 左辺にしかない field は右辺の field domain 外なので conflict になる。
Associative-array and object rest constraints
associative-array constraint は {...T} と書き、object の任意の field value へ T を適用する。
Services = {...{
port = Int;
enabled = Bool default true;
}};
key は列挙されず、空 object も許容される。
named field を持つ object の末尾へ ...T を書くと、列挙されていない field だけに T を適用できる。
{
enabled = Bool default true;
...Unknown
}
rest constraint は field を生成しない。 実在する追加 field の検証にだけ使われる。
default
default は constraint ではない。
materialize 時に concrete value がない場合だけ使われる fallback である。
Port = Int & >= 1 & <= 65535;
Service = {
port = Port default 8080;
};
明示値が合成された場合は明示値が使われ、default は評価されない。
Config = {
port = 9000;
} as Service;
明示値がない場合、materialize 時に 8080 が採用され、Port を満たすか検証される。
default composition
&で片方だけがdefaultを持つ場合、そのdefaultは保持される。&で両辺が異なるdefaultを持つ場合は conflict になる。- constraint と concrete value の
&が成功した場合、結果は concrete value になりdefaultは残らない。 //は右辺優先なので、同じ field では右辺の値またはdefaultが左辺を置き換える。asは右辺のdefaultを左辺へ注入しない。ただし右辺にだけ存在する field は、その field が持つdefaultとともに abstract なまま結果へ残る。
default expression は materialize 時に必要になった時点で評価され、同じ range の constraint を満たす必要がある。