// SPDX-License-Identifier: Apache-2.0
///|
/// Stable categories for the additive checked entry point. Syntax details stay
/// in the diagnostic; they are not inferred from localized error messages.
pub(all) enum ParseError {
InvalidLimits(String)
ResourceLimitExceeded(String)
UnknownFormat(String)
InvalidData(MeshFormat, String)
}
///|
pub fn ParseError::code(self : ParseError) -> String {
match self {
InvalidLimits(_) => "invalid_limits"
ResourceLimitExceeded(_) => "resource_limit"
UnknownFormat(_) => "unknown_format"
InvalidData(_, _) => "invalid_data"
}
}
///|
pub fn ParseError::message(self : ParseError) -> String {
match self {
InvalidLimits(message)
| ResourceLimitExceeded(message)
| UnknownFormat(message)
| InvalidData(_, message) => message
}
}
///|
pub fn MeshFormat::id(self : MeshFormat) -> String {
match self {
Ascii => "stl-ascii"
Binary => "stl-binary"
Obj => "obj"
ThreeMF => "3mf"
Ply => "ply"
Unknown => "unknown"
}
}
///|
pub fn ParseError::to_json(self : ParseError) -> Json {
let format = match self {
InvalidData(format, _) => Json(format.id())
_ => Json::null()
}
Json::object({
"code": Json(self.code()),
"message": Json(self.message()),
"format": format,
"location": Json::null(),
})
}
///|
/// Content-routed parsing with stable coarse error categories. Existing string
/// APIs remain available. InvalidIndex/InvalidHeader are deliberately not
/// guessed from diagnostic prose; location is currently unavailable.
///
/// ```moonbit nocheck
/// match @stlkit.parse_mesh_checked(data) {
/// Ok(mesh) => println(mesh.triangle_count())
/// Err(error) => println(error.code())
/// }
/// ```
pub fn parse_mesh_checked(
data : Bytes,
limits~ : ParseLimits = ParseLimits::default(),
) -> Result[Mesh, ParseError] {
if parse_limits_error(limits) is Some(message) {
return Err(InvalidLimits(message))
}
if input_limit_error(data, limits) is Some(message) {
return Err(ResourceLimitExceeded(message))
}
let format = detect_format(data)
match parse_mesh(data, limits~) {
Ok(mesh) => Ok(mesh)
Err(message) =>
// This reserved leading marker is emitted only by resource_error(), not
// by copied user tokens or localized syntax diagnostics.
if message.has_prefix("resource_limit: ") {
Err(ResourceLimitExceeded(message))
} else if format is Unknown {
Err(UnknownFormat(message))
} else {
Err(InvalidData(format, message))
}
}
}