Add bilingual manual and localized docs routes
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
# Constraints and Defaults
|
||||
|
||||
A constraint describes a range that a value must satisfy.
|
||||
|
||||
```dcdl
|
||||
Int
|
||||
String
|
||||
>= 1
|
||||
<= 65535
|
||||
/Hello! .*/
|
||||
```
|
||||
|
||||
Constraints can be composed with `&`.
|
||||
|
||||
```dcdl
|
||||
Port = Int & >= 1 & <= 65535;
|
||||
NarrowedPort = Port & > 443;
|
||||
```
|
||||
|
||||
The result is the range that satisfies both sides.
|
||||
Incompatible constraints produce a conflict.
|
||||
|
||||
```dcdl
|
||||
Int & String # conflict
|
||||
> 10 & < 5 # conflict
|
||||
Int & > 10 & < 11 # conflict: integer candidate does not exist
|
||||
```
|
||||
|
||||
## Primitive and comparison constraints
|
||||
|
||||
The built-in primitive ranges are:
|
||||
|
||||
```dcdl
|
||||
String
|
||||
Int
|
||||
Float
|
||||
Bool
|
||||
```
|
||||
|
||||
Composing different primitive types with `&` produces a conflict.
|
||||
Numeric comparison constraints combine as bounds and conflict if they form an empty range.
|
||||
|
||||
```dcdl
|
||||
Int & >= 1 & <= 65535 & > 443
|
||||
```
|
||||
|
||||
Comparison constraints for `Int` use integer literals.
|
||||
Comparison constraints for `Float` may use either integer or float literals.
|
||||
|
||||
## Unknown
|
||||
|
||||
`Unknown` is the top range containing every Decodal value.
|
||||
It is not an `Any` that disables checking and erases concrete information; it means that the value's range has not yet been narrowed.
|
||||
|
||||
```dcdl
|
||||
Int & Unknown # Int
|
||||
42 as Unknown # 42
|
||||
Unknown as Int # conflict
|
||||
```
|
||||
|
||||
`Unknown` has no concrete value of its own and therefore cannot be materialized.
|
||||
It must be narrowed by a concrete value or given a `default`.
|
||||
|
||||
```dcdl
|
||||
Unknown default {}
|
||||
```
|
||||
|
||||
## Regex constraints
|
||||
|
||||
A regex literal is a string constraint.
|
||||
|
||||
```dcdl
|
||||
Host = /^api-[0-9]+$/;
|
||||
```
|
||||
|
||||
When several regex constraints are composed, a concrete string must match all of them.
|
||||
|
||||
```dcdl
|
||||
String & /^a/ & /z$/
|
||||
```
|
||||
|
||||
The intersection of regex constraints is not determined during composition.
|
||||
The following range therefore does not conflict when composed, but fails when a concrete value is validated.
|
||||
|
||||
```dcdl
|
||||
String & /^a$/ & /^b$/
|
||||
```
|
||||
|
||||
In the Rust runtime, enable the regex engine with the `regex` feature.
|
||||
Without that feature, validating a regex constraint against a concrete value produces an unsupported-feature diagnostic.
|
||||
|
||||
## Array constraints
|
||||
|
||||
Write an array constraint as `[...T]`; it applies `T` to every element.
|
||||
The element constraint is required.
|
||||
|
||||
```dcdl
|
||||
Names = [...String];
|
||||
PositiveInts = [...(Int & > 0)];
|
||||
```
|
||||
|
||||
When composed with a concrete array, each element is refined against `T` using the same rules as `as`.
|
||||
An empty array satisfies every array constraint.
|
||||
|
||||
If the element constraint is an object range, fields present only on the right remain abstract in every element.
|
||||
A field present only on the left is outside the right-hand field domain and produces a conflict.
|
||||
|
||||
## Associative-array and object rest constraints
|
||||
|
||||
Write an associative-array constraint as `{...T}`; it applies `T` to every field value in an object.
|
||||
|
||||
```dcdl
|
||||
Services = {...{
|
||||
port = Int;
|
||||
enabled = Bool default true;
|
||||
}};
|
||||
```
|
||||
|
||||
Keys are not enumerated, and an empty object is allowed.
|
||||
Writing `...T` at the end of an object with named fields applies `T` only to fields that were not named explicitly.
|
||||
|
||||
```dcdl
|
||||
{
|
||||
enabled = Bool default true;
|
||||
...Unknown
|
||||
}
|
||||
```
|
||||
|
||||
A rest constraint does not generate fields.
|
||||
It only validates additional fields that actually exist.
|
||||
|
||||
## default
|
||||
|
||||
`default` is not a constraint.
|
||||
It is a fallback used only when no concrete value exists during materialization.
|
||||
|
||||
```dcdl
|
||||
Port = Int & >= 1 & <= 65535;
|
||||
|
||||
Service = {
|
||||
port = Port default 8080;
|
||||
};
|
||||
```
|
||||
|
||||
When an explicit value has been composed into the range, that value is used and `default` is not evaluated.
|
||||
|
||||
```dcdl
|
||||
Config = {
|
||||
port = 9000;
|
||||
} as Service;
|
||||
```
|
||||
|
||||
Without an explicit value, materialization selects `8080` and verifies that it satisfies `Port`.
|
||||
|
||||
## Default composition
|
||||
|
||||
- If only one side of `&` has a `default`, that `default` is preserved.
|
||||
- If both sides of `&` have different defaults, they conflict.
|
||||
- If `&` between a constraint and a concrete value succeeds, the result is concrete and does not retain the `default`.
|
||||
- Because `//` is right-biased, the right-hand value or `default` replaces the left-hand one for the same field.
|
||||
- `as` does not inject a right-hand `default` into the left side. A field that exists only on the right, however, remains abstract in the result together with its `default`.
|
||||
|
||||
A `default` expression is evaluated when materialization requires it and must satisfy the constraints of the same range.
|
||||
Reference in New Issue
Block a user