What rvt-rs can and cannot do today, grouped by Revit release, file type, decoded element class, and IFC4 export detail. Every row here is checked against current source code. If a claim in this file disagrees with the source, the source wins and this file is wrong. For the shorter user-facing status summary, see docs/status.md.
Scope sources:
- Version gates:
src/basic_file_info.rs,src/streams.rs,src/walker.rs,tests/common/mod.rs. - File-type support:
src/reader.rs,src/lib.rs,src/bin/*.rs. - Decoder registry:
src/elements/mod.rsall_decoders(). - IFC emission:
src/ifc/category_map.rs,src/ifc/from_decoded.rs,src/ifc/entities.rs.
Integration corpus: Autodesk's public rac_basic_sample_family RFA, one file per Revit release 2016 through 2026, exercised by tests/samples.rs via ALL_YEARS = [2016..=2026] in tests/common/mod.rs.
| Revit release | BasicFileInfo year |
Partitions/NN marker |
OLE + schema + metadata | Schema-directed walker (ADocument) |
|---|---|---|---|---|
| 2016 | 2016 | Partitions/58 | full | partial |
| 2017 | 2017 | Partitions/60 | full | partial |
| 2018 | 2018 | Partitions/61 | full | partial |
| 2019 | 2019 | Partitions/62 | full | partial |
| 2020 | 2020 | Partitions/63 | full | partial |
| 2021 | 2021 | Partitions/64 | full | partial |
| 2022 | 2022 | Partitions/65 | full | partial |
| 2023 | 2023 | Partitions/66 | full | partial |
| 2024 | 2024 | Partitions/67 | full | full |
| 2025 | 2025 | Partitions/68 | full | full |
| 2026 | 2026 | Partitions/69 | full | full |
Column definitions:
- OLE + schema + metadata: opens the CFB container, reads all 13 invariant streams, decompresses
Formats/Latest, parses the full class schema (395 classes on the 2024 sample, 13,570 fields at 100% type classification across the 11-release corpus), extractsBasicFileInfo(version / build / GUID / path / locale), parsesPartAtomXML, extracts theRevitPreview4.0PNG thumbnail, decodesContents, and decodes the 167-byteGlobal/PartitionTableinvariant. This row isfullfor every supported release. - Schema-directed walker:
walker::read_adocumentlocates theADocumententry point inGlobal/Latestand walks all declared fields. Reliable on Revit 2024–2026. ReturnsOk(None)on 2016–2023 when the entry-point detector can't find a high-confidence offset (seewalker.rs§366–370 anddocs/rvt-phase4c-session-2026-04-19.md). This is also the bridge the Layer-5b per-class decoders depend on at runtime against real files.
Before 2016 and after 2026: unverified. The schema parser and compression path are likely to still work on near-future releases because the truncated-gzip and Formats/Latest framing have not changed in a decade, but no corpus entry exists outside [2016, 2026], so nothing is claimed.
All four extensions share the same Microsoft Compound File Binary container, the same stream layout, and the same schema. RevitFile::open dispatches purely on the CFB magic D0 CF 11 E0 A1 B1 1A E1, not on the extension, so the same code path handles all four.
| Type | Extension | Read | IFC4 export |
|---|---|---|---|
| Project | .rvt |
yes | partial: spatial tree/diagnostics; typed elements depend on decoded coverage |
| Family | .rfa |
yes | partial: same pipeline |
| Project template | .rte |
yes | partial: same pipeline |
| Family template | .rft |
yes | partial: same pipeline |
Notes:
- The entire 11-release reference corpus is
.rfa(family) files..rvt/.rte/.rftread the same OLE container and are handled by the same code, but the corpus does not yet include project or template fixtures, so nothing is claimed about.rvt-specific streams that do not appear in families (worksharing metadata, linked-model tables, transmission data beyond the already-decodedTransmissionData). - The CLI binaries (
rvt-info,rvt-analyze,rvt-schema,rvt-history,rvt-diff,rvt-corpus,rvt-dump,rvt-doc,rvt-ifc) accept any of the four extensions without special-casing.
80 decoder structs are registered today. Counted directly from src/elements/mod.rs all_decoders() — the walker dispatch table built at runtime. Grouped by domain below.
Each decoder takes schema-directed instance bytes (from walker::decode_instance) and projects them into a typed Rust struct. Decoders are validated on synthesized schema+bytes fixtures; real-file corpus validation is tracked as Q-01 in the recon report.
Column(structural.rs)StructuralColumn(structural.rs)Beam(structural.rs)StructuralFraming(structural.rs)StructuralFoundation(foundation_and_furnishings.rs)Rebar(foundation_and_furnishings.rs)ReferencePlane(reference_planes.rs)
Wall,WallType(wall.rs)Floor,FloorType(floor.rs)Roof,RoofType(roof.rs)Ceiling,CeilingType(ceiling.rs)Door,Window(openings.rs)CurtainWall,CurtainGrid,CurtainMullion,CurtainPanel(curtain_wall.rs)
Stair,StairType(circulation.rs)Railing,RailingType(circulation.rs)Room,Area,Space(zones.rs)
Furniture,FurnitureSystem,Casework(foundation_and_furnishings.rs)Mass,GenericModel(generic.rs)FamilyInstance(family.rs)
Level(level.rs)Grid,GridType(grid.rs)BasePoint,SurveyPoint,ProjectPosition(reference_points.rs)
Material(styling.rs)FillPattern(styling.rs)LinePattern(styling.rs)LineStyle(styling.rs)
Category,Subcategory(category.rs)Phase,DesignOption,Workset,Revision(project_organization.rs)Symbol(family.rs)
View,Sheet,Schedule,ScheduleView(drafting.rs)- (ReferencePlane is counted under Structural above because its primary consumer is layout, not drafting views.)
Dimension,Tag,TextNote,Annotation(annotations.rs)- Dimensions include linear / angular / radial / arc-length subtypes via the
DimensionKinddiscriminator projected from the schema; tag orientation and horizontal alignment enums are exposed onTagOrientationandHorizontalAlignment.
ParameterElement,SharedParameter(parameters.rs)- Both expose the
StorageTypeenum (None,Integer,Double,String,ElementId,Other) so callers can route parameter values into property-set emission (see §4 IFC-31). AProperty,APropertyBoolean,APropertyInteger,APropertyEnum,APropertyDouble1,APropertyDouble3,APropertyFloat,APropertyFloat3(parameters.rs)- These value-carrier decoders are building blocks for parameter extraction. Real-file parameter recovery still depends on the object-graph and partition-record linkage described in
docs/status.md.
- Electrical:
ElectricalEquipment,ElectricalFixture,LightingFixture,LightingDevice(mep.rs) - Mechanical:
Duct,DuctFitting,MechanicalEquipment(mep.rs) - Plumbing:
Pipe,PipeFitting,PlumbingFixture(mep.rs) - Generic MEP:
SpecialtyEquipment(mep.rs) - All MEP instances project onto a shared
MepInstancetyped view with an optionalMepSystemClassification(Supply / Return / Exhaust / …) so IFC distribution-system emission (IFC-10, future) can key off it without re-reading the schema.
Group sum: 7 + 13 + 7 + 6 + 6 + 4 + 7 + 5 + 4 + 10 + 11 = 80, matching all_decoders().len().
The bridge ifc::build_ifc_model maps each decoded element to an IfcEntity::BuildingElement, and ifc::write_step serialises the model as an IFC4 STEP file. A fixed spatial hierarchy (IfcProject → IfcSite → IfcBuilding → IfcBuildingStorey) always ships; per-element shape / material / property-set emission is per-class.
Column definitions:
- IFC entity + placement: a valid
IfcWall/IfcSlab/ … is constructed and wired to the storey viaIfcRelContainedInSpatialStructure. Always yes for every Revit class that has a mapping incategory_map.rs; unknown classes fall back toIfcBuildingElementProxyrather than being dropped. - Extruded geometry: an
IfcRectangleProfileDef+IfcExtrudedAreaSolid+IfcShapeRepresentation+IfcProductDefinitionShapechain is emitted and attached to the element'sRepresentationslot, iff the caller supplies anExtrusionvia one of the helpers infrom_decoded.rs(wall_extrusion,slab_extrusion,roof_extrusion,ceiling_extrusion,column_extrusion). The helpers exist for the classes marked "yes"; they do not exist yet for the classes marked "no helper". - Material association: an
IfcMaterial+IfcRelAssociatesMaterialis emitted iff the caller populatesBuilderOptions.materials(seematerials_from_revit) and setsElementInput.material_index. For compound hosts,ElementInput.material_layer_set_indexroutes through anIfcMaterialLayerSet+IfcMaterialLayerSetUsagechain (IFC-28 / IFC-29); for profile-driven members,material_profile_set_indexroutes throughIfcMaterialProfileSet+IfcMaterialProfileSetUsage(IFC-30). Precedence order isprofile_set > layer_set > single material— whichever is set wins. - Property set: an
IfcPropertySet+IfcPropertySingleValue+IfcRelDefinesByProperties(IFC-31 / IFC-33) is emitted iff the caller supplies aPropertySetvia a dedicated helper (wall_property_set,door_property_set,window_property_set,stair_property_setexist today). Quantity-typed properties route throughIfcQuantityArea/IfcQuantityVolume/IfcQuantityCount/IfcQuantityTime/IfcQuantityWeight(IFC-32), with Imperial-to-SI conversion done at emission time (square-feet → m², cubic-feet → m³, pounds → kg). - Opening / fill: for doors / windows, iff the caller sets
host_element_indexandextrusionon the opening, the writer emitsIfcOpeningElement+IfcRelVoidsElement(host → opening, IFC-37) +IfcRelFillsElement(opening → door/window, IFC-38).
| Revit class | IFC entity | Placement + storey | Extrusion helper | Material assoc | Property set | Opening / fill |
|---|---|---|---|---|---|---|
| Level | IfcBuildingStorey | built-in | n/a | n/a | n/a | n/a |
| Grid | IfcGrid | yes | no helper | n/a | n/a | n/a |
| Wall | IfcWall (STANDARD) | yes | yes (wall_extrusion) |
yes | yes (wall_property_set) |
n/a |
| CurtainWall | IfcCurtainWall | yes | no helper | no helper | no helper | n/a |
| Door | IfcDoor | yes | caller-supplied | yes | yes (door_property_set) |
yes |
| Window | IfcWindow | yes | caller-supplied | yes | yes (window_property_set) |
yes |
| Floor | IfcSlab (FLOOR) | yes | yes (slab_extrusion) |
yes | no helper | n/a |
| Roof | IfcRoof | yes | yes (roof_extrusion) |
yes | no helper | n/a |
| Ceiling | IfcCovering (CEILING) | yes | yes (ceiling_extrusion) |
yes | no helper | n/a |
| Stair | IfcStair | yes | no helper | yes | yes (stair_property_set) |
n/a |
| Railing | IfcRailing | yes | no helper | yes | no helper | n/a |
| Ramp | IfcRamp | yes | no helper | yes | no helper | n/a |
| Column | IfcColumn (COLUMN) | yes | yes (column_extrusion) |
yes | no helper | n/a |
| StructuralColumn | IfcColumn (COLUMN) | yes | yes (column_extrusion) |
yes | no helper | n/a |
| StructuralFraming | IfcBeam (BEAM) | yes | no helper | yes | no helper | n/a |
| StructuralFoundation | IfcFooting | yes | no helper | yes | no helper | n/a |
| Rebar | IfcReinforcingBar | yes | no helper | yes | no helper | n/a |
| Room | IfcSpace (INTERNAL) | yes | no helper | n/a | no helper | n/a |
| Area | IfcSpace | yes | no helper | n/a | no helper | n/a |
| Space | IfcSpace | yes | no helper | n/a | no helper | n/a |
| Furniture | IfcFurniture | yes | no helper | yes | no helper | n/a |
| FurnitureSystem | IfcFurniture (USERDEFINED) | yes | no helper | yes | no helper | n/a |
| Casework | IfcFurniture | yes | no helper | yes | no helper | n/a |
| LightingFixture | IfcLightFixture | yes | no helper | yes | no helper | n/a |
| LightingDevice | IfcLightFixture (USERDEFINED) | yes | no helper | yes | no helper | n/a |
| ElectricalEquipment | IfcElectricAppliance | yes | no helper | yes | no helper | n/a |
| ElectricalFixture | IfcLightFixture | yes | no helper | yes | no helper | n/a |
| MechanicalEquipment | IfcFlowController | yes | no helper | yes | no helper | n/a |
| Duct | IfcDuctSegment | yes | no helper | yes | no helper | n/a |
| DuctFitting | IfcDuctFitting | yes | no helper | yes | no helper | n/a |
| Pipe | IfcPipeSegment | yes | no helper | yes | no helper | n/a |
| PipeFitting | IfcPipeFitting | yes | no helper | yes | no helper | n/a |
| PlumbingFixture | IfcSanitaryTerminal | yes | no helper | yes | no helper | n/a |
| SpecialtyEquipment | IfcBuildingElementProxy (USERDEFINED) | yes | no helper | yes | no helper | n/a |
| Mass | IfcBuildingElementProxy (USERDEFINED) | yes | no helper | n/a | no helper | n/a |
| GenericModel | IfcBuildingElementProxy | yes | no helper | n/a | no helper | n/a |
| (unknown class) | IfcBuildingElementProxy | yes | n/a | n/a | n/a | n/a |
Notes:
- "Yes (mapped; decoder pending)" rows: the class has a category-map entry and would round-trip through the bridge if a decoder existed, but no
ElementDecoderfor the class is registered inall_decoders()today, so the bridge never sees a decoded instance to map. See §3 MEP note. - The units slot is populated via
BuilderOptions.units(typically fromRvtDocExporter::build_unit_list) and emits asIfcUnitAssignment. Classifications (OmniClass / Uniformat fromPartAtom) emit asIfcClassification+IfcClassificationReference. - The STEP writer is deterministic under
write_step_with_options(model, StepOptions { timestamp })— a fixedtimestampproduces byte-identical output across runs. Unicode escaping is ISO-10303-21-correct (BMP\X2\HHHH\X0\, supplementary\X4\HHHHHHHH\X0\, backslash doubled, control chars\X\HH). - A committed sample IFC output lives at
tests/fixtures/synthetic-project.ifcand is exercised bytests/ifc_synthetic_project.rs. It opens cleanly in BlenderBIM / IfcOpenShell spatial browsers.
- No semantic write path for Revit files. Stream-level patching (
writer::write_with_patches) can replace the bytes of a named stream, re-compress with truncated gzip, and re-embed into a byte-preserving sibling file (13/13 streams identical on the 2024 sample round-trip). Field-level semantic writes (edit a specific Wall's unconnected height and round-trip back to a Revit-openable.rvt) are not implemented. - No format versions before Revit 2016. Earlier Revit releases used a different compression + schema framing that this library has not been probed against. No claim is made about 2015-or-earlier.
- No IFC2X3 or IFC4.3 export. The STEP writer targets IFC4 only. The category map is structured to make a future IFC2X3 / IFC4.3 swap a table replacement, but it has not been swapped.
- No encrypted or password-protected files. Revit's "Protected" models use a wrapper format this library does not attempt to strip. CFB open will succeed on the outer container but inner streams will be gibberish.
- No linked-model resolution.
.rvtprojects can carry references to external.rvt/.rfa/.rcp/.dwg/.ifcfiles; this library reads the host file's CFB streams but does not follow or resolve links. Any linked-model metadata is exposed only as raw bytes on whichever stream carries it (TransmissionDataon project files). - MEP geometry extraction. The 11 MEP classes listed in §3 decode their schema metadata (class, name, family-instance linkage, system classification), but the geometric centerline / 3D path of ducts, pipes, conduits, and cable-trays is not yet extracted — the IFC rows above ship an
IfcDuctSegment/IfcPipeSegmentwith placement and spatial-containment but noIfcShapeRepresentation. Routing-path recovery is tracked as a Phase-5 extension once the curve-graph decoder lands. - Annotation geometry. The 4 annotation classes (
Dimension,Tag,TextNote,Annotation) decode the annotation-element data (anchor points, text contents, orientation, witness-line references) but do not yet render 2D annotation graphics into IFC presentation layers. Drawn sheets therefore export asIfcAnnotationshells without the witness-line / leader / dimension-string geometry that a plotted sheet would need. - Schema-directed walker is partial on 2016–2023. See §1. The stream layout and entry-point heuristics differ pre-2024;
read_adocumentreturnsOk(None)when it can't find a high-confidence offset instead of returning possibly-wrong fields. - Geometry extraction is Phase 5. The IFC export produces valid placement and extruded rectangular solids when the caller supplies dimensions. The reader now recovers rough rectangular swept solids for the Revit 2023 Einhoven ArcWall record layout, but arbitrary wall layouts, 2024+ ArcWall records, floors, doors, windows, profile shapes, and brep geometry are still pending. The Extrusion helpers in
from_decoded.rsremain the general bridge for caller-supplied dimensions. - Parcel of unparsed streams.
Global/DocumentIncrementTable,Global/History,Global/ContentDocuments, andPartitions/NNchunks beyond the first are enumerated and decompressed but their internal framing is only partially reverse-engineered (see recon report §Q6 and §Q7).