ianmackenzie/elm-iso-10303/2.0.0

NOTE: the latest version is 8.0.1

Formerly ianmackenzie/elm-step-file. Search finds this package by either name.

Step.Decode

This module lets you decode data from STEP files in a similar way to how you decode JSON.

Decoder types

type Decoder i m a

A Decoder describes how to attempt to decode some input of type i (an entire file, an individual entity, a specific attribute) and produce some output of type a.

Entity decoders have the additional ability to choose whether to match a particular entity. For example, a decoder for CARTESIAN_POINT entities would fail if it encountered a CARTESIAN_POINT in an unexpected format (no XYZ coordinates, for example) but would not match a DIRECTION entity. This distinction is important to avoid silently swallowing errors.

The m type parameter indicates whether a decoder has this ability to match or not match inputs; it is equal to String for entity decoders and Never otherwise.

You will rarely use the Decoder type directly in your own code, instead using the specialized types such as EntityDecoder, but you will likely see it in compiler error messages so it is useful to understand what the type parameters mean.

type alias FileDecoder a =
Decoder File Never a

A Decoder that takes an entire STEP file as input and produces some output.

type alias EntityDecoder a =
Decoder Entity String a

A Decoder that takes a STEP entity as input, chooses whether or not it should 'match' that entity (generally based on the entity's type), and then (if it matches) decode that entity to produce some output.

type alias AttributeListDecoder a =
Decoder (List Attribute) Never a

A Decoder that takes a list of entity attributes as input and produces some output. The only AttributeListDecoder is attribute, which selects a particular attribute from the list by index and then applies a given AttributeDecoder to that attribute.

type alias AttributeDecoder a =
Decoder Attribute Never a

A Decoder that takes a single entity attribute as input and produces some output.

type Error
= ParseError String
| NonexistentEntity Int
| CircularReference (List Int)
| DecodeError String

Different kinds of errors that may be encountered when loading a STEP file:

  • ParseError: the file could not be parsed as a valid STEP file.
  • NonexistentEntity: one entity in the STEP file refers to another by integer ID, but no entity with that ID exists in the file.
  • CircularReference: There exists a circular chain of entities in the file that refer to each other; the List Int is the list of entity IDs in the chain.
  • DecodeError: the file was parsed OK and all entity references were resolved successfully, but an error occurred when running the given decoder.

Decoding a file

file : FileDecoder a -> String -> Result Error a

Decode a STEP file given as a String using the given decoder. For example, to extract the file header and all CARTESIAN_POINT entities from a given file, you might write:

import Step.File
import Step.Decode as Decode exposing
    ( Decoder
    , FileDecoder
    , EntityDecoder
    )


type alias FileData =
    { header : Step.File.Header
    , points : List ( Float, Float, Float )
    }


pointDecoder : EntityDecoder ( Float, Float, Float )
pointDecoder =
    Decode.entity "CARTESIAN_POINT" <|
        Decode.attribute 1 (Decode.tuple3 Decode.float)


fileDecoder : FileDecoder FileData
fileDecoder =
    Decode.map2 FileData
        Decode.header
        (Decode.all pointDecoder)


fileContents : String
fileContents =
    "ISO-10303-21;...END-ISO-10303-21;"


decoded : Result Decode.Error FileData
decoded =
    Decode.file fileDecoder fileContents
single : EntityDecoder a -> FileDecoder a

Attempt to find exactly one entity in a file that matches the given decoder. If there are no matching entities or more than one matching entity, the decoder will fail.

all : EntityDecoder a -> FileDecoder (List a)

Find all entities in a file matching the given decoder.

Decoding an entity

entity : String -> AttributeListDecoder a -> EntityDecoder a

Decode an entity of the given type name, using the given decoder on the entity's list of attributes. If this decoder is passed to single or all, any entities that do not have the given type will be skipped.

Decoding attribute lists

attribute : Int -> AttributeDecoder a -> AttributeListDecoder a

Decode a specific attribute by index (starting from 0) in an attribute list. To decode data from multiple attributes in a list, you can use one of the mapN functions, for example:

type alias MyAttributes =
    { name : String
    , age : Int
    , height : Float
    }


myAttributesDecoder : AttributeListDecoder MyAttributes
myAttributesDecoder =
    Decode.map3 MyAttributes
        (Decode.attribute 0 Decode.string)
        (Decode.attribute 1 Decode.int)
        (Decode.attribute 2 Decode.float)

Decoding attributes

bool : AttributeDecoder Bool

Decode a single attribute as a Bool (from the special STEP enum values .T. and .F.).

int : AttributeDecoder Int

Decode a single attribute as an Int.

float : AttributeDecoder Float

Decode a single attribute as a Float. Note that unlike JSON, STEP has different encodings for Int and Float values so you cannot use this function to decode integer values; if you want to decode an integer value as a Float you will need to use

Decode.map toFloat Decode.int
string : AttributeDecoder String

Decode a single attribute as a String.

enum : List ( String, a ) -> AttributeDecoder a

Decode a single enum attribute, by passing a list of enum cases as their STEP type name and corresponding Elm value. For example, given a STEP enum with values .RED., .YELLOW. and .GREEN. you might write:

type LightColor
    = Red
    | Yellow
    | Green


lightColorDecoder : AttributeDecoder LightColor
lightColorDecoder =
    Decode.enum
        [ ( "RED", Red )
        , ( "YELLOW", Yellow )
        , ( "GREEN", Green )
        ]

(Note that the given strings will be normalized, so you do not have to worry about upper vs. lower case and you can either include or omit the leading and trailing periods.)

referenceTo : EntityDecoder a -> AttributeDecoder a

Decode an attribute which is a reference to another entity, by providing the decoder to use for that entity.

null : a -> AttributeDecoder a

Decode the special 'null' attribute ($) as the given value.

optional : AttributeDecoder a -> AttributeDecoder (Maybe a)

Decode an attribute that may be null, returning Nothing if it is.

list : AttributeDecoder a -> AttributeDecoder (List a)

Decode an attribute as a list, passing the decoder to be used for each list item.

tuple2 : AttributeDecoder a -> AttributeDecoder ( a, a )

Decode a list of exactly two elements, passing the decoder to be used for the two elements.

tuple3 : AttributeDecoder a -> AttributeDecoder ( a, a, a )

Decode a list of exactly three elements, passing the decoder to be used for the three elements.

derived : a -> AttributeDecoder a

Decode the special 'derived value' attribute (*) as the given value.

Typed attributes

boolAs : String -> AttributeDecoder Bool

Decode a Bool wrapped as the given type.

intAs : String -> AttributeDecoder Int

Decode an Int wrapped as the given type.

floatAs : String -> AttributeDecoder Float

Decode a Float wrapped as the given type.

stringAs : String -> AttributeDecoder String

Decode a String wrapped as the given type.

enumAs : String -> List ( String, a ) -> AttributeDecoder a

Decode an enum wrapped as the given type.

listAs : String -> AttributeDecoder a -> AttributeDecoder (List a)

Decode a list wrapped as the given type.

Working with decoders

succeed : a -> Decoder i m a

A special decoder that always succeeds with the given value. Primarily useful with andThen.

fail : String -> Decoder i m a

A special decoder that always fails with the given error message.

map : (a -> b) -> Decoder i m a -> Decoder i m b

Map the value produced by a decoder.

map2 : (a -> b -> c) -> Decoder i m a -> Decoder i m b -> Decoder i m c

Map over two decoders.

(a -> b -> c -> d)
-> Decoder i m a
-> Decoder i m b
-> Decoder i m c
-> Decoder i m d

Map over three decoders.

(a -> b -> c -> d -> e)
-> Decoder i m a
-> Decoder i m b
-> Decoder i m c
-> Decoder i m d
-> Decoder i m e

Map over four decoders.

(a -> b -> c -> d -> e -> f)
-> Decoder i m a
-> Decoder i m b
-> Decoder i m c
-> Decoder i m d
-> Decoder i m e
-> Decoder i m f

Map over five decoders.

(a -> b -> c -> d -> e -> f -> g)
-> Decoder i m a
-> Decoder i m b
-> Decoder i m c
-> Decoder i m d
-> Decoder i m e
-> Decoder i m f
-> Decoder i m g

Map over six decoders.

(a -> b -> c -> d -> e -> f -> g -> h)
-> Decoder i m a
-> Decoder i m b
-> Decoder i m c
-> Decoder i m d
-> Decoder i m e
-> Decoder i m f
-> Decoder i m g
-> Decoder i m h

Map over seven decoders.

(a -> b -> c -> d -> e -> f -> g -> h -> j)
-> Decoder i m a
-> Decoder i m b
-> Decoder i m c
-> Decoder i m d
-> Decoder i m e
-> Decoder i m f
-> Decoder i m g
-> Decoder i m h
-> Decoder i m j

Map over eight decoders.

andThen : (a -> Decoder i Never b) -> Decoder i m a -> Decoder i m b

Run one decoder, and based on the result of the first decoder decide what decoder to apply next. The only restriction is that this second decoder must be of a type that always matches (so not an entity decoder), since it is the first decoder that decides whether to match the input or not.

oneOf : List (EntityDecoder a) -> EntityDecoder a

Construct an entity decoder that may match one of many entity types.

lazy : (() -> Decoder i m a) -> Decoder i m a

Define a decoder lazily such that it is only constructed if needed. This is primarily used to break circular reference chains between decoders.