use std::error::Error;
use std::fmt;
const MESSAGE_ROW_OUT_OF_RANGE: &str = "row is outside the supported Excel range";
const MESSAGE_COLUMN_OUT_OF_RANGE: &str = "column is outside the supported Excel range";
const MESSAGE_CELL_ADDRESS_INVALID: &str = "cell address is not valid A1 notation";
const MESSAGE_RANGE_REVERSED: &str = "range start must not be after range end";
const MESSAGE_SHEET_ID_ZERO: &str = "sheet ID must be greater than zero";
const MESSAGE_SHEET_NAME_EMPTY: &str = "sheet name must not be empty";
const MESSAGE_SHEET_NAME_TOO_LONG: &str = "sheet name exceeds 31 UTF-16 code units";
const MESSAGE_SHEET_NAME_INVALID_CHARACTER: &str = "sheet name contains an invalid character";
const MESSAGE_SHEET_NAME_APOSTROPHE_BOUNDARY: &str =
"sheet name must not begin or end with an apostrophe";
const MESSAGE_DUPLICATE_SHEET_ID: &str = "workbook contains a duplicate sheet ID";
const MESSAGE_DUPLICATE_SHEET_NAME: &str =
"workbook contains a duplicate case-insensitive sheet name";
const MESSAGE_DUPLICATE_CELL: &str = "sheet contains a duplicate cell address";
const MESSAGE_DEFINED_NAME_EMPTY: &str = "defined name must not be empty";
const MESSAGE_DEFINED_NAME_TOO_LONG: &str = "defined name exceeds 255 UTF-16 code units";
const MESSAGE_DEFINED_NAME_CONTROL: &str = "defined name contains a control character";
const MESSAGE_DEFINED_NAME_UNKNOWN_SHEET: &str = "defined name scope references an unknown sheet";
const MESSAGE_DUPLICATE_DEFINED_NAME: &str =
"workbook contains a duplicate case-insensitive defined name in one scope";
const MESSAGE_NON_FINITE_NUMBER: &str = "cell number must be finite";
const MESSAGE_FORMULA_EMPTY: &str = "formula text must not be empty";
const MESSAGE_XLSX_FORMULA_EQUALS: &str =
"XLSX formula text must not include a leading equals sign";
const MESSAGE_USER_FORMULA_EQUALS: &str = "user formula text must begin with an equals sign";
const MESSAGE_SOURCE_ID_EMPTY: &str = "source ID must not be empty";
const MESSAGE_DIAGNOSTIC_CODE_INVALID: &str =
"diagnostic code must use lowercase dotted identifiers";
const MESSAGE_PROVIDER_NAME_EMPTY: &str = "provider name must not be empty";
const MESSAGE_PROVIDER_VERSION_EMPTY: &str = "provider version must not be empty";
const MESSAGE_DIAGNOSTIC_MESSAGE_EMPTY: &str = "diagnostic message must not be empty";
const MESSAGE_UNKNOWN_SHEET_ID: &str = "workbook does not contain the requested sheet ID";
const MESSAGE_CELL_NOT_FOUND: &str = "workbook does not contain the requested cell";
const MESSAGE_SHEET_ID_EXHAUSTED: &str = "workbook cannot allocate another sheet ID";
const MESSAGE_LAST_VISIBLE_SHEET: &str = "workbook must retain at least one visible sheet";
const MESSAGE_SEMANTIC_REVISION_EXHAUSTED: &str = "workbook semantic revision is exhausted";
const MESSAGE_PRESENTATION_REVISION_EXHAUSTED: &str = "workbook presentation revision is exhausted";
const MESSAGE_PHONETIC_RANGE_EMPTY: &str = "phonetic text range start must be less than its end";
const MESSAGE_PHONETIC_RANGE_OUT_OF_BOUNDS: &str = "phonetic text range exceeds the base text";
const MESSAGE_PHONETIC_RANGE_SPLITS_SURROGATE: &str =
"phonetic text range must use UTF-16 character boundaries";
const MESSAGE_PHONETIC_RUNS_OUT_OF_ORDER: &str =
"phonetic runs must be ordered and non-overlapping";
const MESSAGE_PHONETIC_TEXT_EMPTY: &str = "phonetic text must not be empty";
const MESSAGE_PHONETIC_TEXT_INVALID_CHARACTER: &str =
"phonetic text contains a character forbidden by XML 1.0";
const MESSAGE_PHONETICS_REQUIRE_TEXT_CELL: &str =
"phonetic annotations require a literal text cell";
const MESSAGE_PHONETIC_FONT_ID_UNSUPPORTED: &str =
"phonetic authoring currently supports only the default font record";
const MESSAGE_ANNOTATED_TEXT_REPLACEMENT_REQUIRED: &str =
"annotated text must be cleared or replaced atomically";
const MESSAGE_FROZEN_ROWS_OUT_OF_RANGE: &str =
"frozen row count cannot produce a valid top-left cell";
const MESSAGE_FROZEN_COLUMNS_OUT_OF_RANGE: &str =
"frozen column count cannot produce a valid top-left cell";
const MESSAGE_TABLE_ID_ZERO: &str = "table ID must be greater than zero";
const MESSAGE_TABLE_COLUMN_ID_ZERO: &str = "table column ID must be greater than zero";
const MESSAGE_TABLE_NAME_EMPTY: &str = "table name must not be empty";
const MESSAGE_TABLE_NAME_TOO_LONG: &str = "table name exceeds 255 UTF-16 code units";
const MESSAGE_TABLE_NAME_INVALID_CHARACTER: &str = "table name contains an invalid character";
const MESSAGE_TABLE_NAME_REFERENCE_CONFLICT: &str =
"table name must not be an A1 or R1C1 reference";
const MESSAGE_DUPLICATE_TABLE_DISPLAY_NAME: &str =
"workbook contains a duplicate case-insensitive table display name";
const MESSAGE_DUPLICATE_TABLE_ID: &str = "workbook contains a duplicate table ID";
const MESSAGE_DUPLICATE_TABLE_PROGRAMMATIC_NAME: &str =
"worksheet contains a duplicate case-insensitive programmatic table name";
const MESSAGE_TABLE_DISPLAY_NAME_CONFLICTS_WITH_DEFINED_NAME: &str =
"table display name conflicts with a workbook defined name";
const MESSAGE_TABLE_COLUMNS_EMPTY: &str = "table must declare at least one column";
const MESSAGE_TABLE_COLUMN_COUNT_MISMATCH: &str =
"table column count does not match the table range width";
const MESSAGE_TABLE_COLUMN_NAME_EMPTY: &str = "table column name must not be empty";
const MESSAGE_TABLE_COLUMN_NAME_TOO_LONG: &str = "table column name exceeds 255 UTF-16 code units";
const MESSAGE_TABLE_COLUMN_NAME_INVALID_CHARACTER: &str =
"table column name contains a character forbidden by XML 1.0";
const MESSAGE_TABLE_COLUMN_NAME_SPACE_BOUNDARY: &str =
"table column name must not begin or end with an ASCII space";
const MESSAGE_DUPLICATE_TABLE_COLUMN_NAME: &str =
"table contains a duplicate case-insensitive column name";
const MESSAGE_DUPLICATE_TABLE_COLUMN_ID: &str = "table contains a duplicate column identifier";
const MESSAGE_OVERLAPPING_TABLES: &str = "worksheet contains overlapping table ranges";
const MESSAGE_TABLE_ROW_COUNTS_EXCEED_RANGE: &str =
"table header and totals rows exceed the table range height";
const MESSAGE_INVALID_TABLE_TOTALS_METADATA: &str =
"table totals label, function, and formula metadata are inconsistent";
const MESSAGE_UNKNOWN_TABLE_ID: &str = "workbook does not contain the requested table ID";
const MESSAGE_UNKNOWN_TABLE_COLUMN_ID: &str = "table does not contain the requested column ID";
const MESSAGE_TABLE_DATA_ROWS_REVERSED: &str = "table data row start must not be after its end";
const MESSAGE_TABLE_RESIZE_HEADER_UNDERFLOW: &str =
"table data row start cannot accommodate the declared header rows";
const MESSAGE_TABLE_MATERIALIZATION_COLLISION: &str =
"table materialization would overwrite non-equivalent worksheet content";
const MESSAGE_UNSUPPORTED_TABLE_AUTHORING_METADATA: &str =
"table metadata cannot be preserved safely by this authoring operation";
const MESSAGE_FORMULA_REWRITE_PARSE_FAILED: &str =
"a formula related to the rename could not be parsed for typed rewriting";
const MESSAGE_NUMBER_FORMAT_BUILTIN_ID: &str = "built-in number format ID must be less than 164";
const MESSAGE_NUMBER_FORMAT_CUSTOM_ID: &str = "custom number format ID must be at least 164";
const MESSAGE_NUMBER_FORMAT_CODE_EMPTY: &str = "custom number format code must not be empty";
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub enum ValidationErrorCode {
RowOutOfRange,
ColumnOutOfRange,
CellAddressInvalid,
RangeStartAfterEnd,
SheetIdZero,
SheetNameEmpty,
SheetNameTooLong,
SheetNameInvalidCharacter,
SheetNameApostropheBoundary,
DuplicateSheetId,
DuplicateSheetName,
DuplicateCell,
DefinedNameEmpty,
DefinedNameTooLong,
DefinedNameControlCharacter,
DefinedNameUnknownSheet,
DuplicateDefinedName,
NonFiniteNumber,
FormulaEmpty,
XlsxFormulaHasLeadingEquals,
UserFormulaMissingLeadingEquals,
SourceIdEmpty,
DiagnosticCodeInvalid,
ProviderNameEmpty,
ProviderVersionEmpty,
DiagnosticMessageEmpty,
UnknownSheetId,
CellNotFound,
SheetIdExhausted,
LastVisibleSheet,
SemanticRevisionExhausted,
PresentationRevisionExhausted,
PhoneticRangeEmpty,
PhoneticRangeOutOfBounds,
PhoneticRangeSplitsSurrogate,
PhoneticRunsOutOfOrder,
PhoneticTextEmpty,
PhoneticTextInvalidCharacter,
PhoneticsRequireTextCell,
PhoneticFontIdUnsupported,
AnnotatedTextReplacementRequired,
FrozenRowsOutOfRange,
FrozenColumnsOutOfRange,
BuiltInNumberFormatId,
CustomNumberFormatId,
NumberFormatCodeEmpty,
TableIdZero,
TableColumnIdZero,
TableNameEmpty,
TableNameTooLong,
TableNameInvalidCharacter,
TableNameReferenceConflict,
DuplicateTableDisplayName,
DuplicateTableId,
DuplicateTableProgrammaticName,
TableDisplayNameConflictsWithDefinedName,
TableColumnsEmpty,
TableColumnCountMismatch,
TableColumnNameEmpty,
TableColumnNameTooLong,
TableColumnNameInvalidCharacter,
TableColumnNameSpaceBoundary,
DuplicateTableColumnName,
DuplicateTableColumnId,
OverlappingTables,
TableRowCountsExceedRange,
InvalidTableTotalsMetadata,
UnknownTableId,
UnknownTableColumnId,
TableDataRowsReversed,
TableResizeHeaderUnderflow,
TableMaterializationCollision,
UnsupportedTableAuthoringMetadata,
FormulaRewriteParseFailed,
}
impl ValidationErrorCode {
pub const fn as_str(self) -> &'static str {
match self {
Self::RowOutOfRange => "validation.row_out_of_range",
Self::ColumnOutOfRange => "validation.column_out_of_range",
Self::CellAddressInvalid => "validation.cell_address_invalid",
Self::RangeStartAfterEnd => "validation.range_start_after_end",
Self::SheetIdZero => "validation.sheet_id_zero",
Self::SheetNameEmpty => "validation.sheet_name_empty",
Self::SheetNameTooLong => "validation.sheet_name_too_long",
Self::SheetNameInvalidCharacter => "validation.sheet_name_invalid_character",
Self::SheetNameApostropheBoundary => "validation.sheet_name_apostrophe_boundary",
Self::DuplicateSheetId => "validation.duplicate_sheet_id",
Self::DuplicateSheetName => "validation.duplicate_sheet_name",
Self::DuplicateCell => "validation.duplicate_cell",
Self::DefinedNameEmpty => "validation.defined_name_empty",
Self::DefinedNameTooLong => "validation.defined_name_too_long",
Self::DefinedNameControlCharacter => "validation.defined_name_control_character",
Self::DefinedNameUnknownSheet => "validation.defined_name_unknown_sheet",
Self::DuplicateDefinedName => "validation.duplicate_defined_name",
Self::NonFiniteNumber => "validation.non_finite_number",
Self::FormulaEmpty => "validation.formula_empty",
Self::XlsxFormulaHasLeadingEquals => "validation.xlsx_formula_has_leading_equals",
Self::UserFormulaMissingLeadingEquals => {
"validation.user_formula_missing_leading_equals"
}
Self::SourceIdEmpty => "validation.source_id_empty",
Self::DiagnosticCodeInvalid => "validation.diagnostic_code_invalid",
Self::ProviderNameEmpty => "validation.provider_name_empty",
Self::ProviderVersionEmpty => "validation.provider_version_empty",
Self::DiagnosticMessageEmpty => "validation.diagnostic_message_empty",
Self::UnknownSheetId => "validation.unknown_sheet_id",
Self::CellNotFound => "validation.cell_not_found",
Self::SheetIdExhausted => "validation.sheet_id_exhausted",
Self::LastVisibleSheet => "validation.last_visible_sheet",
Self::SemanticRevisionExhausted => "validation.semantic_revision_exhausted",
Self::PresentationRevisionExhausted => "validation.presentation_revision_exhausted",
Self::PhoneticRangeEmpty => "validation.phonetic_range_empty",
Self::PhoneticRangeOutOfBounds => "validation.phonetic_range_out_of_bounds",
Self::PhoneticRangeSplitsSurrogate => "validation.phonetic_range_splits_surrogate",
Self::PhoneticRunsOutOfOrder => "validation.phonetic_runs_out_of_order",
Self::PhoneticTextEmpty => "validation.phonetic_text_empty",
Self::PhoneticTextInvalidCharacter => "validation.phonetic_text_invalid_character",
Self::PhoneticsRequireTextCell => "validation.phonetics_require_text_cell",
Self::PhoneticFontIdUnsupported => "validation.phonetic_font_id_unsupported",
Self::AnnotatedTextReplacementRequired => {
"validation.annotated_text_replacement_required"
}
Self::FrozenRowsOutOfRange => "validation.frozen_rows_out_of_range",
Self::FrozenColumnsOutOfRange => "validation.frozen_columns_out_of_range",
Self::BuiltInNumberFormatId => "validation.built_in_number_format_id",
Self::CustomNumberFormatId => "validation.custom_number_format_id",
Self::NumberFormatCodeEmpty => "validation.number_format_code_empty",
Self::TableIdZero => "validation.table_id_zero",
Self::TableColumnIdZero => "validation.table_column_id_zero",
Self::TableNameEmpty => "validation.table_name_empty",
Self::TableNameTooLong => "validation.table_name_too_long",
Self::TableNameInvalidCharacter => "validation.table_name_invalid_character",
Self::TableNameReferenceConflict => "validation.table_name_reference_conflict",
Self::DuplicateTableDisplayName => "validation.duplicate_table_display_name",
Self::DuplicateTableId => "validation.duplicate_table_id",
Self::DuplicateTableProgrammaticName => "validation.duplicate_table_programmatic_name",
Self::TableDisplayNameConflictsWithDefinedName => {
"validation.table_display_name_conflicts_with_defined_name"
}
Self::TableColumnsEmpty => "validation.table_columns_empty",
Self::TableColumnCountMismatch => "validation.table_column_count_mismatch",
Self::TableColumnNameEmpty => "validation.table_column_name_empty",
Self::TableColumnNameTooLong => "validation.table_column_name_too_long",
Self::TableColumnNameInvalidCharacter => {
"validation.table_column_name_invalid_character"
}
Self::TableColumnNameSpaceBoundary => "validation.table_column_name_space_boundary",
Self::DuplicateTableColumnName => "validation.duplicate_table_column_name",
Self::DuplicateTableColumnId => "validation.duplicate_table_column_id",
Self::OverlappingTables => "validation.overlapping_tables",
Self::TableRowCountsExceedRange => "validation.table_row_counts_exceed_range",
Self::InvalidTableTotalsMetadata => "validation.invalid_table_totals_metadata",
Self::UnknownTableId => "validation.unknown_table_id",
Self::UnknownTableColumnId => "validation.unknown_table_column_id",
Self::TableDataRowsReversed => "validation.table_data_rows_reversed",
Self::TableResizeHeaderUnderflow => "validation.table_resize_header_underflow",
Self::TableMaterializationCollision => "validation.table_materialization_collision",
Self::UnsupportedTableAuthoringMetadata => {
"validation.unsupported_table_authoring_metadata"
}
Self::FormulaRewriteParseFailed => "validation.formula_rewrite_parse_failed",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ValidationError {
RowOutOfRange {
value: u32,
},
ColumnOutOfRange {
value: u32,
},
CellAddressInvalid,
RangeStartAfterEnd,
SheetIdZero,
SheetNameEmpty,
SheetNameTooLong {
utf16_len: usize,
},
SheetNameInvalidCharacter {
character: char,
},
SheetNameApostropheBoundary,
DuplicateSheetId {
value: u32,
},
DuplicateSheetName {
name: String,
},
DuplicateCell {
row: u32,
column: u32,
},
DefinedNameEmpty,
DefinedNameTooLong {
utf16_len: usize,
},
DefinedNameControlCharacter {
character: char,
},
DefinedNameUnknownSheet {
sheet_id: u32,
},
DuplicateDefinedName {
name: String,
},
NonFiniteNumber,
FormulaEmpty,
XlsxFormulaHasLeadingEquals,
UserFormulaMissingLeadingEquals,
SourceIdEmpty,
DiagnosticCodeInvalid,
ProviderNameEmpty,
ProviderVersionEmpty,
DiagnosticMessageEmpty,
UnknownSheetId {
value: u32,
},
CellNotFound {
sheet_id: u32,
row: u32,
column: u32,
},
SheetIdExhausted,
LastVisibleSheet,
SemanticRevisionExhausted,
PresentationRevisionExhausted,
PhoneticRangeEmpty {
start: u32,
end: u32,
},
PhoneticRangeOutOfBounds {
end: u32,
base_utf16_len: u32,
},
PhoneticRangeSplitsSurrogate {
offset: u32,
},
PhoneticRunsOutOfOrder,
PhoneticTextEmpty,
PhoneticTextInvalidCharacter {
character: char,
},
PhoneticsRequireTextCell {
sheet_id: u32,
row: u32,
column: u32,
},
PhoneticFontIdUnsupported {
value: u32,
},
AnnotatedTextReplacementRequired {
sheet_id: u32,
row: u32,
column: u32,
},
FrozenRowsOutOfRange {
value: u32,
},
FrozenColumnsOutOfRange {
value: u32,
},
BuiltInNumberFormatId {
value: u32,
},
CustomNumberFormatId {
value: u32,
},
NumberFormatCodeEmpty,
TableIdZero,
TableColumnIdZero,
TableNameEmpty,
TableNameTooLong {
utf16_len: usize,
},
TableNameInvalidCharacter {
character: char,
},
TableNameReferenceConflict,
DuplicateTableDisplayName {
name: String,
},
DuplicateTableId {
id: u32,
},
DuplicateTableProgrammaticName {
name: String,
},
TableDisplayNameConflictsWithDefinedName {
name: String,
},
TableColumnsEmpty,
TableColumnCountMismatch {
columns: usize,
width: u32,
},
TableColumnNameEmpty,
TableColumnNameTooLong {
utf16_len: usize,
},
TableColumnNameInvalidCharacter {
character: char,
},
TableColumnNameSpaceBoundary,
DuplicateTableColumnName {
name: String,
},
DuplicateTableColumnId {
id: u32,
},
OverlappingTables {
sheet_id: u32,
first_table_id: u32,
second_table_id: u32,
},
TableRowCountsExceedRange {
header_row_count: u32,
totals_row_count: u32,
height: u32,
},
InvalidTableTotalsMetadata,
UnknownTableId {
value: u32,
},
UnknownTableColumnId {
table_id: u32,
column_id: u32,
},
TableDataRowsReversed {
first_data_row: u32,
last_data_row: u32,
},
TableResizeHeaderUnderflow {
table_id: u32,
first_data_row: u32,
header_row_count: u32,
},
TableMaterializationCollision {
table_id: u32,
sheet_id: u32,
row: u32,
column: u32,
},
UnsupportedTableAuthoringMetadata {
table_id: u32,
},
FormulaRewriteParseFailed {
parse_code: String,
start: usize,
end: usize,
owner: Option<String>,
},
}
impl ValidationError {
pub const fn code(&self) -> ValidationErrorCode {
match self {
Self::RowOutOfRange { .. } => ValidationErrorCode::RowOutOfRange,
Self::ColumnOutOfRange { .. } => ValidationErrorCode::ColumnOutOfRange,
Self::CellAddressInvalid => ValidationErrorCode::CellAddressInvalid,
Self::RangeStartAfterEnd => ValidationErrorCode::RangeStartAfterEnd,
Self::SheetIdZero => ValidationErrorCode::SheetIdZero,
Self::SheetNameEmpty => ValidationErrorCode::SheetNameEmpty,
Self::SheetNameTooLong { .. } => ValidationErrorCode::SheetNameTooLong,
Self::SheetNameInvalidCharacter { .. } => {
ValidationErrorCode::SheetNameInvalidCharacter
}
Self::SheetNameApostropheBoundary => ValidationErrorCode::SheetNameApostropheBoundary,
Self::DuplicateSheetId { .. } => ValidationErrorCode::DuplicateSheetId,
Self::DuplicateSheetName { .. } => ValidationErrorCode::DuplicateSheetName,
Self::DuplicateCell { .. } => ValidationErrorCode::DuplicateCell,
Self::DefinedNameEmpty => ValidationErrorCode::DefinedNameEmpty,
Self::DefinedNameTooLong { .. } => ValidationErrorCode::DefinedNameTooLong,
Self::DefinedNameControlCharacter { .. } => {
ValidationErrorCode::DefinedNameControlCharacter
}
Self::DefinedNameUnknownSheet { .. } => ValidationErrorCode::DefinedNameUnknownSheet,
Self::DuplicateDefinedName { .. } => ValidationErrorCode::DuplicateDefinedName,
Self::NonFiniteNumber => ValidationErrorCode::NonFiniteNumber,
Self::FormulaEmpty => ValidationErrorCode::FormulaEmpty,
Self::XlsxFormulaHasLeadingEquals => ValidationErrorCode::XlsxFormulaHasLeadingEquals,
Self::UserFormulaMissingLeadingEquals => {
ValidationErrorCode::UserFormulaMissingLeadingEquals
}
Self::SourceIdEmpty => ValidationErrorCode::SourceIdEmpty,
Self::DiagnosticCodeInvalid => ValidationErrorCode::DiagnosticCodeInvalid,
Self::ProviderNameEmpty => ValidationErrorCode::ProviderNameEmpty,
Self::ProviderVersionEmpty => ValidationErrorCode::ProviderVersionEmpty,
Self::DiagnosticMessageEmpty => ValidationErrorCode::DiagnosticMessageEmpty,
Self::UnknownSheetId { .. } => ValidationErrorCode::UnknownSheetId,
Self::CellNotFound { .. } => ValidationErrorCode::CellNotFound,
Self::SheetIdExhausted => ValidationErrorCode::SheetIdExhausted,
Self::LastVisibleSheet => ValidationErrorCode::LastVisibleSheet,
Self::SemanticRevisionExhausted => ValidationErrorCode::SemanticRevisionExhausted,
Self::PresentationRevisionExhausted => {
ValidationErrorCode::PresentationRevisionExhausted
}
Self::PhoneticRangeEmpty { .. } => ValidationErrorCode::PhoneticRangeEmpty,
Self::PhoneticRangeOutOfBounds { .. } => ValidationErrorCode::PhoneticRangeOutOfBounds,
Self::PhoneticRangeSplitsSurrogate { .. } => {
ValidationErrorCode::PhoneticRangeSplitsSurrogate
}
Self::PhoneticRunsOutOfOrder => ValidationErrorCode::PhoneticRunsOutOfOrder,
Self::PhoneticTextEmpty => ValidationErrorCode::PhoneticTextEmpty,
Self::PhoneticTextInvalidCharacter { .. } => {
ValidationErrorCode::PhoneticTextInvalidCharacter
}
Self::PhoneticsRequireTextCell { .. } => ValidationErrorCode::PhoneticsRequireTextCell,
Self::PhoneticFontIdUnsupported { .. } => {
ValidationErrorCode::PhoneticFontIdUnsupported
}
Self::AnnotatedTextReplacementRequired { .. } => {
ValidationErrorCode::AnnotatedTextReplacementRequired
}
Self::FrozenRowsOutOfRange { .. } => ValidationErrorCode::FrozenRowsOutOfRange,
Self::FrozenColumnsOutOfRange { .. } => ValidationErrorCode::FrozenColumnsOutOfRange,
Self::BuiltInNumberFormatId { .. } => ValidationErrorCode::BuiltInNumberFormatId,
Self::CustomNumberFormatId { .. } => ValidationErrorCode::CustomNumberFormatId,
Self::NumberFormatCodeEmpty => ValidationErrorCode::NumberFormatCodeEmpty,
Self::TableIdZero => ValidationErrorCode::TableIdZero,
Self::TableColumnIdZero => ValidationErrorCode::TableColumnIdZero,
Self::TableNameEmpty => ValidationErrorCode::TableNameEmpty,
Self::TableNameTooLong { .. } => ValidationErrorCode::TableNameTooLong,
Self::TableNameInvalidCharacter { .. } => {
ValidationErrorCode::TableNameInvalidCharacter
}
Self::TableNameReferenceConflict => ValidationErrorCode::TableNameReferenceConflict,
Self::DuplicateTableDisplayName { .. } => {
ValidationErrorCode::DuplicateTableDisplayName
}
Self::DuplicateTableId { .. } => ValidationErrorCode::DuplicateTableId,
Self::DuplicateTableProgrammaticName { .. } => {
ValidationErrorCode::DuplicateTableProgrammaticName
}
Self::TableDisplayNameConflictsWithDefinedName { .. } => {
ValidationErrorCode::TableDisplayNameConflictsWithDefinedName
}
Self::TableColumnsEmpty => ValidationErrorCode::TableColumnsEmpty,
Self::TableColumnCountMismatch { .. } => ValidationErrorCode::TableColumnCountMismatch,
Self::TableColumnNameEmpty => ValidationErrorCode::TableColumnNameEmpty,
Self::TableColumnNameTooLong { .. } => ValidationErrorCode::TableColumnNameTooLong,
Self::TableColumnNameInvalidCharacter { .. } => {
ValidationErrorCode::TableColumnNameInvalidCharacter
}
Self::TableColumnNameSpaceBoundary => ValidationErrorCode::TableColumnNameSpaceBoundary,
Self::DuplicateTableColumnName { .. } => ValidationErrorCode::DuplicateTableColumnName,
Self::DuplicateTableColumnId { .. } => ValidationErrorCode::DuplicateTableColumnId,
Self::OverlappingTables { .. } => ValidationErrorCode::OverlappingTables,
Self::TableRowCountsExceedRange { .. } => {
ValidationErrorCode::TableRowCountsExceedRange
}
Self::InvalidTableTotalsMetadata => ValidationErrorCode::InvalidTableTotalsMetadata,
Self::UnknownTableId { .. } => ValidationErrorCode::UnknownTableId,
Self::UnknownTableColumnId { .. } => ValidationErrorCode::UnknownTableColumnId,
Self::TableDataRowsReversed { .. } => ValidationErrorCode::TableDataRowsReversed,
Self::TableResizeHeaderUnderflow { .. } => {
ValidationErrorCode::TableResizeHeaderUnderflow
}
Self::TableMaterializationCollision { .. } => {
ValidationErrorCode::TableMaterializationCollision
}
Self::UnsupportedTableAuthoringMetadata { .. } => {
ValidationErrorCode::UnsupportedTableAuthoringMetadata
}
Self::FormulaRewriteParseFailed { .. } => {
ValidationErrorCode::FormulaRewriteParseFailed
}
}
}
}
impl fmt::Display for ValidationError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::RowOutOfRange { value } => {
write!(formatter, "{MESSAGE_ROW_OUT_OF_RANGE}: {value}")
}
Self::ColumnOutOfRange { value } => {
write!(formatter, "{MESSAGE_COLUMN_OUT_OF_RANGE}: {value}")
}
Self::CellAddressInvalid => formatter.write_str(MESSAGE_CELL_ADDRESS_INVALID),
Self::RangeStartAfterEnd => formatter.write_str(MESSAGE_RANGE_REVERSED),
Self::SheetIdZero => formatter.write_str(MESSAGE_SHEET_ID_ZERO),
Self::SheetNameEmpty => formatter.write_str(MESSAGE_SHEET_NAME_EMPTY),
Self::SheetNameTooLong { utf16_len } => {
write!(formatter, "{MESSAGE_SHEET_NAME_TOO_LONG}: {utf16_len}")
}
Self::SheetNameInvalidCharacter { character } => write!(
formatter,
"{MESSAGE_SHEET_NAME_INVALID_CHARACTER}: {character:?}"
),
Self::SheetNameApostropheBoundary => {
formatter.write_str(MESSAGE_SHEET_NAME_APOSTROPHE_BOUNDARY)
}
Self::DuplicateSheetId { value } => {
write!(formatter, "{MESSAGE_DUPLICATE_SHEET_ID}: {value}")
}
Self::DuplicateSheetName { name } => {
write!(formatter, "{MESSAGE_DUPLICATE_SHEET_NAME}: {name}")
}
Self::DuplicateCell { row, column } => {
write!(
formatter,
"{MESSAGE_DUPLICATE_CELL}: row {row}, column {column}"
)
}
Self::DefinedNameEmpty => formatter.write_str(MESSAGE_DEFINED_NAME_EMPTY),
Self::DefinedNameTooLong { utf16_len } => {
write!(formatter, "{MESSAGE_DEFINED_NAME_TOO_LONG}: {utf16_len}")
}
Self::DefinedNameControlCharacter { character } => {
write!(formatter, "{MESSAGE_DEFINED_NAME_CONTROL}: {character:?}")
}
Self::DefinedNameUnknownSheet { sheet_id } => {
write!(
formatter,
"{MESSAGE_DEFINED_NAME_UNKNOWN_SHEET}: {sheet_id}"
)
}
Self::DuplicateDefinedName { name } => {
write!(formatter, "{MESSAGE_DUPLICATE_DEFINED_NAME}: {name}")
}
Self::NonFiniteNumber => formatter.write_str(MESSAGE_NON_FINITE_NUMBER),
Self::FormulaEmpty => formatter.write_str(MESSAGE_FORMULA_EMPTY),
Self::XlsxFormulaHasLeadingEquals => formatter.write_str(MESSAGE_XLSX_FORMULA_EQUALS),
Self::UserFormulaMissingLeadingEquals => {
formatter.write_str(MESSAGE_USER_FORMULA_EQUALS)
}
Self::SourceIdEmpty => formatter.write_str(MESSAGE_SOURCE_ID_EMPTY),
Self::DiagnosticCodeInvalid => formatter.write_str(MESSAGE_DIAGNOSTIC_CODE_INVALID),
Self::ProviderNameEmpty => formatter.write_str(MESSAGE_PROVIDER_NAME_EMPTY),
Self::ProviderVersionEmpty => formatter.write_str(MESSAGE_PROVIDER_VERSION_EMPTY),
Self::DiagnosticMessageEmpty => formatter.write_str(MESSAGE_DIAGNOSTIC_MESSAGE_EMPTY),
Self::UnknownSheetId { value } => {
write!(formatter, "{MESSAGE_UNKNOWN_SHEET_ID}: {value}")
}
Self::CellNotFound {
sheet_id,
row,
column,
} => write!(
formatter,
"{MESSAGE_CELL_NOT_FOUND}: sheet {sheet_id}, row {row}, column {column}"
),
Self::SheetIdExhausted => formatter.write_str(MESSAGE_SHEET_ID_EXHAUSTED),
Self::LastVisibleSheet => formatter.write_str(MESSAGE_LAST_VISIBLE_SHEET),
Self::SemanticRevisionExhausted => {
formatter.write_str(MESSAGE_SEMANTIC_REVISION_EXHAUSTED)
}
Self::PresentationRevisionExhausted => {
formatter.write_str(MESSAGE_PRESENTATION_REVISION_EXHAUSTED)
}
Self::PhoneticRangeEmpty { start, end } => {
write!(formatter, "{MESSAGE_PHONETIC_RANGE_EMPTY}: {start}..{end}")
}
Self::PhoneticRangeOutOfBounds {
end,
base_utf16_len,
} => write!(
formatter,
"{MESSAGE_PHONETIC_RANGE_OUT_OF_BOUNDS}: {end} > {base_utf16_len}"
),
Self::PhoneticRangeSplitsSurrogate { offset } => {
write!(
formatter,
"{MESSAGE_PHONETIC_RANGE_SPLITS_SURROGATE}: {offset}"
)
}
Self::PhoneticRunsOutOfOrder => formatter.write_str(MESSAGE_PHONETIC_RUNS_OUT_OF_ORDER),
Self::PhoneticTextEmpty => formatter.write_str(MESSAGE_PHONETIC_TEXT_EMPTY),
Self::PhoneticTextInvalidCharacter { character } => write!(
formatter,
"{MESSAGE_PHONETIC_TEXT_INVALID_CHARACTER}: {character:?}"
),
Self::PhoneticsRequireTextCell {
sheet_id,
row,
column,
} => write!(
formatter,
"{MESSAGE_PHONETICS_REQUIRE_TEXT_CELL}: sheet {sheet_id}, row {row}, column {column}"
),
Self::PhoneticFontIdUnsupported { value } => {
write!(formatter, "{MESSAGE_PHONETIC_FONT_ID_UNSUPPORTED}: {value}")
}
Self::AnnotatedTextReplacementRequired {
sheet_id,
row,
column,
} => write!(
formatter,
"{MESSAGE_ANNOTATED_TEXT_REPLACEMENT_REQUIRED}: sheet {sheet_id}, row {row}, column {column}"
),
Self::FrozenRowsOutOfRange { value } => {
write!(formatter, "{MESSAGE_FROZEN_ROWS_OUT_OF_RANGE}: {value}")
}
Self::FrozenColumnsOutOfRange { value } => {
write!(formatter, "{MESSAGE_FROZEN_COLUMNS_OUT_OF_RANGE}: {value}")
}
Self::BuiltInNumberFormatId { value } => {
write!(formatter, "{MESSAGE_NUMBER_FORMAT_BUILTIN_ID}: {value}")
}
Self::CustomNumberFormatId { value } => {
write!(formatter, "{MESSAGE_NUMBER_FORMAT_CUSTOM_ID}: {value}")
}
Self::NumberFormatCodeEmpty => formatter.write_str(MESSAGE_NUMBER_FORMAT_CODE_EMPTY),
Self::TableIdZero => formatter.write_str(MESSAGE_TABLE_ID_ZERO),
Self::TableColumnIdZero => formatter.write_str(MESSAGE_TABLE_COLUMN_ID_ZERO),
Self::TableNameEmpty => formatter.write_str(MESSAGE_TABLE_NAME_EMPTY),
Self::TableNameTooLong { utf16_len } => {
write!(formatter, "{MESSAGE_TABLE_NAME_TOO_LONG}: {utf16_len}")
}
Self::TableNameInvalidCharacter { character } => write!(
formatter,
"{MESSAGE_TABLE_NAME_INVALID_CHARACTER}: {character:?}"
),
Self::TableNameReferenceConflict => {
formatter.write_str(MESSAGE_TABLE_NAME_REFERENCE_CONFLICT)
}
Self::DuplicateTableDisplayName { name } => {
write!(formatter, "{MESSAGE_DUPLICATE_TABLE_DISPLAY_NAME}: {name}")
}
Self::DuplicateTableId { id } => {
write!(formatter, "{MESSAGE_DUPLICATE_TABLE_ID}: {id}")
}
Self::DuplicateTableProgrammaticName { name } => {
write!(
formatter,
"{MESSAGE_DUPLICATE_TABLE_PROGRAMMATIC_NAME}: {name}"
)
}
Self::TableDisplayNameConflictsWithDefinedName { name } => {
write!(
formatter,
"{MESSAGE_TABLE_DISPLAY_NAME_CONFLICTS_WITH_DEFINED_NAME}: {name}"
)
}
Self::TableColumnsEmpty => formatter.write_str(MESSAGE_TABLE_COLUMNS_EMPTY),
Self::TableColumnCountMismatch { columns, width } => write!(
formatter,
"{MESSAGE_TABLE_COLUMN_COUNT_MISMATCH}: {columns} columns, width {width}"
),
Self::TableColumnNameEmpty => formatter.write_str(MESSAGE_TABLE_COLUMN_NAME_EMPTY),
Self::TableColumnNameTooLong { utf16_len } => {
write!(
formatter,
"{MESSAGE_TABLE_COLUMN_NAME_TOO_LONG}: {utf16_len}"
)
}
Self::TableColumnNameInvalidCharacter { character } => write!(
formatter,
"{MESSAGE_TABLE_COLUMN_NAME_INVALID_CHARACTER}: {character:?}"
),
Self::TableColumnNameSpaceBoundary => {
formatter.write_str(MESSAGE_TABLE_COLUMN_NAME_SPACE_BOUNDARY)
}
Self::DuplicateTableColumnName { name } => {
write!(formatter, "{MESSAGE_DUPLICATE_TABLE_COLUMN_NAME}: {name}")
}
Self::DuplicateTableColumnId { id } => {
write!(formatter, "{MESSAGE_DUPLICATE_TABLE_COLUMN_ID}: {id}")
}
Self::OverlappingTables {
sheet_id,
first_table_id,
second_table_id,
} => write!(
formatter,
"{MESSAGE_OVERLAPPING_TABLES}: sheet {sheet_id}, tables {first_table_id} and {second_table_id}"
),
Self::TableRowCountsExceedRange {
header_row_count,
totals_row_count,
height,
} => write!(
formatter,
"{MESSAGE_TABLE_ROW_COUNTS_EXCEED_RANGE}: header {header_row_count}, totals {totals_row_count}, height {height}"
),
Self::InvalidTableTotalsMetadata => {
formatter.write_str(MESSAGE_INVALID_TABLE_TOTALS_METADATA)
}
Self::UnknownTableId { value } => {
write!(formatter, "{MESSAGE_UNKNOWN_TABLE_ID}: {value}")
}
Self::UnknownTableColumnId {
table_id,
column_id,
} => write!(
formatter,
"{MESSAGE_UNKNOWN_TABLE_COLUMN_ID}: table {table_id}, column {column_id}"
),
Self::TableDataRowsReversed {
first_data_row,
last_data_row,
} => write!(
formatter,
"{MESSAGE_TABLE_DATA_ROWS_REVERSED}: {first_data_row}..{last_data_row}"
),
Self::TableResizeHeaderUnderflow {
table_id,
first_data_row,
header_row_count,
} => write!(
formatter,
"{MESSAGE_TABLE_RESIZE_HEADER_UNDERFLOW}: table {table_id}, first data row {first_data_row}, header rows {header_row_count}"
),
Self::TableMaterializationCollision {
table_id,
sheet_id,
row,
column,
} => write!(
formatter,
"{MESSAGE_TABLE_MATERIALIZATION_COLLISION}: table {table_id}, sheet {sheet_id}, row {row}, column {column}"
),
Self::UnsupportedTableAuthoringMetadata { table_id } => write!(
formatter,
"{MESSAGE_UNSUPPORTED_TABLE_AUTHORING_METADATA}: table {table_id}"
),
Self::FormulaRewriteParseFailed {
parse_code,
start,
end,
owner,
} => {
write!(
formatter,
"{MESSAGE_FORMULA_REWRITE_PARSE_FAILED}: {parse_code} at {start}..{end}"
)?;
if let Some(owner) = owner {
write!(formatter, ", owner {owner}")?;
}
Ok(())
}
}
}
}
impl Error for ValidationError {}
#[cfg(test)]
mod tests {
use std::collections::BTreeSet;
use super::ValidationErrorCode;
#[test]
fn validation_error_code_strings_are_complete_stable_and_unique() {
let cases = [
(
ValidationErrorCode::RowOutOfRange,
"validation.row_out_of_range",
),
(
ValidationErrorCode::ColumnOutOfRange,
"validation.column_out_of_range",
),
(
ValidationErrorCode::CellAddressInvalid,
"validation.cell_address_invalid",
),
(
ValidationErrorCode::RangeStartAfterEnd,
"validation.range_start_after_end",
),
(ValidationErrorCode::SheetIdZero, "validation.sheet_id_zero"),
(
ValidationErrorCode::SheetNameEmpty,
"validation.sheet_name_empty",
),
(
ValidationErrorCode::SheetNameTooLong,
"validation.sheet_name_too_long",
),
(
ValidationErrorCode::SheetNameInvalidCharacter,
"validation.sheet_name_invalid_character",
),
(
ValidationErrorCode::SheetNameApostropheBoundary,
"validation.sheet_name_apostrophe_boundary",
),
(
ValidationErrorCode::DuplicateSheetId,
"validation.duplicate_sheet_id",
),
(
ValidationErrorCode::DuplicateSheetName,
"validation.duplicate_sheet_name",
),
(
ValidationErrorCode::DuplicateCell,
"validation.duplicate_cell",
),
(
ValidationErrorCode::DefinedNameEmpty,
"validation.defined_name_empty",
),
(
ValidationErrorCode::DefinedNameTooLong,
"validation.defined_name_too_long",
),
(
ValidationErrorCode::DefinedNameControlCharacter,
"validation.defined_name_control_character",
),
(
ValidationErrorCode::DefinedNameUnknownSheet,
"validation.defined_name_unknown_sheet",
),
(
ValidationErrorCode::DuplicateDefinedName,
"validation.duplicate_defined_name",
),
(
ValidationErrorCode::NonFiniteNumber,
"validation.non_finite_number",
),
(
ValidationErrorCode::FormulaEmpty,
"validation.formula_empty",
),
(
ValidationErrorCode::XlsxFormulaHasLeadingEquals,
"validation.xlsx_formula_has_leading_equals",
),
(
ValidationErrorCode::UserFormulaMissingLeadingEquals,
"validation.user_formula_missing_leading_equals",
),
(
ValidationErrorCode::SourceIdEmpty,
"validation.source_id_empty",
),
(
ValidationErrorCode::DiagnosticCodeInvalid,
"validation.diagnostic_code_invalid",
),
(
ValidationErrorCode::ProviderNameEmpty,
"validation.provider_name_empty",
),
(
ValidationErrorCode::ProviderVersionEmpty,
"validation.provider_version_empty",
),
(
ValidationErrorCode::DiagnosticMessageEmpty,
"validation.diagnostic_message_empty",
),
(
ValidationErrorCode::UnknownSheetId,
"validation.unknown_sheet_id",
),
(
ValidationErrorCode::CellNotFound,
"validation.cell_not_found",
),
(
ValidationErrorCode::SheetIdExhausted,
"validation.sheet_id_exhausted",
),
(
ValidationErrorCode::LastVisibleSheet,
"validation.last_visible_sheet",
),
(
ValidationErrorCode::SemanticRevisionExhausted,
"validation.semantic_revision_exhausted",
),
(
ValidationErrorCode::PresentationRevisionExhausted,
"validation.presentation_revision_exhausted",
),
(
ValidationErrorCode::PhoneticRangeEmpty,
"validation.phonetic_range_empty",
),
(
ValidationErrorCode::PhoneticRangeOutOfBounds,
"validation.phonetic_range_out_of_bounds",
),
(
ValidationErrorCode::PhoneticRangeSplitsSurrogate,
"validation.phonetic_range_splits_surrogate",
),
(
ValidationErrorCode::PhoneticRunsOutOfOrder,
"validation.phonetic_runs_out_of_order",
),
(
ValidationErrorCode::PhoneticTextEmpty,
"validation.phonetic_text_empty",
),
(
ValidationErrorCode::PhoneticTextInvalidCharacter,
"validation.phonetic_text_invalid_character",
),
(
ValidationErrorCode::PhoneticsRequireTextCell,
"validation.phonetics_require_text_cell",
),
(
ValidationErrorCode::PhoneticFontIdUnsupported,
"validation.phonetic_font_id_unsupported",
),
(
ValidationErrorCode::AnnotatedTextReplacementRequired,
"validation.annotated_text_replacement_required",
),
(
ValidationErrorCode::FrozenRowsOutOfRange,
"validation.frozen_rows_out_of_range",
),
(
ValidationErrorCode::FrozenColumnsOutOfRange,
"validation.frozen_columns_out_of_range",
),
(
ValidationErrorCode::BuiltInNumberFormatId,
"validation.built_in_number_format_id",
),
(
ValidationErrorCode::CustomNumberFormatId,
"validation.custom_number_format_id",
),
(
ValidationErrorCode::NumberFormatCodeEmpty,
"validation.number_format_code_empty",
),
(ValidationErrorCode::TableIdZero, "validation.table_id_zero"),
(
ValidationErrorCode::TableColumnIdZero,
"validation.table_column_id_zero",
),
(
ValidationErrorCode::TableNameEmpty,
"validation.table_name_empty",
),
(
ValidationErrorCode::TableNameTooLong,
"validation.table_name_too_long",
),
(
ValidationErrorCode::TableNameInvalidCharacter,
"validation.table_name_invalid_character",
),
(
ValidationErrorCode::TableNameReferenceConflict,
"validation.table_name_reference_conflict",
),
(
ValidationErrorCode::DuplicateTableDisplayName,
"validation.duplicate_table_display_name",
),
(
ValidationErrorCode::DuplicateTableId,
"validation.duplicate_table_id",
),
(
ValidationErrorCode::DuplicateTableProgrammaticName,
"validation.duplicate_table_programmatic_name",
),
(
ValidationErrorCode::TableDisplayNameConflictsWithDefinedName,
"validation.table_display_name_conflicts_with_defined_name",
),
(
ValidationErrorCode::TableColumnsEmpty,
"validation.table_columns_empty",
),
(
ValidationErrorCode::TableColumnCountMismatch,
"validation.table_column_count_mismatch",
),
(
ValidationErrorCode::TableColumnNameEmpty,
"validation.table_column_name_empty",
),
(
ValidationErrorCode::TableColumnNameTooLong,
"validation.table_column_name_too_long",
),
(
ValidationErrorCode::TableColumnNameInvalidCharacter,
"validation.table_column_name_invalid_character",
),
(
ValidationErrorCode::TableColumnNameSpaceBoundary,
"validation.table_column_name_space_boundary",
),
(
ValidationErrorCode::DuplicateTableColumnName,
"validation.duplicate_table_column_name",
),
(
ValidationErrorCode::DuplicateTableColumnId,
"validation.duplicate_table_column_id",
),
(
ValidationErrorCode::OverlappingTables,
"validation.overlapping_tables",
),
(
ValidationErrorCode::TableRowCountsExceedRange,
"validation.table_row_counts_exceed_range",
),
(
ValidationErrorCode::InvalidTableTotalsMetadata,
"validation.invalid_table_totals_metadata",
),
(
ValidationErrorCode::UnknownTableId,
"validation.unknown_table_id",
),
(
ValidationErrorCode::UnknownTableColumnId,
"validation.unknown_table_column_id",
),
(
ValidationErrorCode::TableDataRowsReversed,
"validation.table_data_rows_reversed",
),
(
ValidationErrorCode::TableResizeHeaderUnderflow,
"validation.table_resize_header_underflow",
),
(
ValidationErrorCode::TableMaterializationCollision,
"validation.table_materialization_collision",
),
(
ValidationErrorCode::UnsupportedTableAuthoringMetadata,
"validation.unsupported_table_authoring_metadata",
),
(
ValidationErrorCode::FormulaRewriteParseFailed,
"validation.formula_rewrite_parse_failed",
),
];
let mut seen_codes = BTreeSet::new();
for (code, expected_text) in &cases {
assert_eq!(code.as_str(), *expected_text);
assert!(seen_codes.insert(*expected_text));
}
assert_eq!(seen_codes.len(), cases.len());
}
}