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