# Constraints
Constraints are checked inside a `new()` constructor on the generated newtype.
The constructor returns `Result<Self, &'static str>`.
## Value range constraints (INTEGER)
```asn1
Port ::= INTEGER (1..65535)
```
Generated Rust:
```rust
pub struct Port(u16);
impl Port {
pub fn new(value: u16) -> std::result::Result<Self, &'static str> {
let val: i64 = value as i64;
if (1..=65535).contains(&val) {
Ok(Self(value))
} else {
Err("must be in range 1..65535")
}
}
pub const fn new_unchecked(value: u16) -> Self { Self(value) }
pub const fn get(&self) -> u16 { self.0 }
pub fn into_inner(self) -> u16 { self.0 }
}
// TryFrom<Integer> for the decode path
impl core::convert::TryFrom<Integer> for Port {
type Error = &'static str;
fn try_from(value: Integer) -> std::result::Result<Self, Self::Error> {
let n = value.as_i64().map_err(|_| "integer value out of i64 range")?;
let v = u16::try_from(n).map_err(|_| "must be in range 1..65535")?;
Self::new(v)
}
}
```
MIN and MAX are accepted as open-ended bounds:
```asn1
LargeId ::= INTEGER (1..MAX)
Count ::= INTEGER (MIN..100)
```
## Size constraints
```asn1
Label ::= UTF8String (SIZE (1..64))
```
Generated Rust:
```rust
pub struct Label(pub synta::Utf8String);
impl Label {
pub fn new(value: synta::Utf8String) -> std::result::Result<Self, &'static str> {
let len = value.as_str().len();
if !(1..=64).contains(&len) {
return Err("Label: size out of range 1..64");
}
Ok(Self(value))
}
pub fn new_unchecked(value: synta::Utf8String) -> Self { Self(value) }
pub fn get(&self) -> &synta::Utf8String { &self.0 }
pub fn as_str(&self) -> &str { self.0.as_str() }
pub fn into_inner(self) -> synta::Utf8String { self.0 }
}
```
Note: `as_str()` is generated for text string types (`IA5String`,
`PrintableString`, `Utf8String`). It is not generated for `OctetString` or
`BitString` constrained newtypes.
## Permitted alphabet (FROM)
```asn1
Upper ::= PrintableString (FROM ("A".."Z"))
```
The `new()` constructor iterates over each character and checks membership in
the permitted set.
## PATTERN constraints
When the `regex` feature is enabled, a static `Lazy<Regex>` is generated and
matched inside `new()`. When the feature is absent, a TODO comment is emitted:
```rust
pub struct Foo(pub synta::PrintableString);
impl Foo {
pub fn new(value: synta::PrintableString) -> std::result::Result<Self, &'static str> {
// TODO: pattern constraint ^[A-Z]{2}$ not validated (enable feature "regex")
Ok(Self(value))
}
}
```
Enable pattern validation by adding the `regex` feature to your **consuming crate**
(not synta itself) and declaring the `regex` and `once_cell` dependencies:
```toml
[features]
regex = ["dep:regex", "dep:once_cell"]
[dependencies]
regex = { version = "1.10", optional = true }
once_cell = { version = "1.19", optional = true }
```
## CONTAINING constraints
When the `validate_containing` feature is enabled in your **consuming crate**,
the constructor decodes the inner type from the raw value using a scratch decoder.
Without the feature, a TODO comment is emitted.
```toml
[features]
validate_containing = []
```
## Named bits
```asn1
KeyUsage ::= BIT STRING {
digitalSignature (0),
keyEncipherment (2)
}
```
Generated Rust:
```rust
pub struct KeyUsage(pub synta::BitString);
impl KeyUsage {
pub const DIGITAL_SIGNATURE: u32 = 0;
pub const KEY_ENCIPHERMENT: u32 = 2;
}
```
## UNION and INTERSECTION
- Union (`|`): `new()` returns `Ok` if any one condition passes.
- Intersection (`^`): `new()` returns `Ok` only if all conditions pass.
- Complement (`ALL EXCEPT`): `new()` returns `Ok` if the inner constraint does
NOT pass.
```asn1
NotReserved ::= INTEGER (ALL EXCEPT (0 | 255))
```
## Inner type constraints
For `SEQUENCE OF` or `SET OF` with element constraints, `new()` iterates over
elements and validates each one.
```asn1
PortList ::= SEQUENCE OF INTEGER (1..65535)
```
The generated `new()` on `PortList` checks that every element is within
`1..65535`.
## Using `new_unchecked`
For data from trusted sources (e.g., already validated in a database), use the
unchecked constructor to skip validation:
```rust
// Trusted source — bypass validation
let port = Port::new_unchecked(8080u16);
// Untrusted source — always validate
let port = Port::new(request_port)?;
```