diff --git a/src/emitter.rs b/src/emitter.rs index a79784f..b98dd5e 100644 --- a/src/emitter.rs +++ b/src/emitter.rs @@ -4,8 +4,8 @@ use crate::api::OUTPUT_BUFFER_SIZE; use crate::macros::{ is_alpha, is_ascii, is_blank, is_blankz, is_bom, is_break, is_printable, is_space, }; -use crate::ops::{ForceAdd as _, ForceMul as _}; -use crate::yaml::{size_t, yaml_char_t, YamlEventData}; +use crate::ops::ForceMul as _; +use crate::yaml::YamlEventData; use crate::{ libc, yaml_emitter_flush, yaml_emitter_t, yaml_event_delete, yaml_event_t, yaml_scalar_style_t, yaml_tag_directive_t, yaml_version_directive_t, YAML_ANY_BREAK, YAML_ANY_ENCODING, @@ -22,7 +22,6 @@ use crate::{ YAML_FOLDED_SCALAR_STYLE, YAML_LITERAL_SCALAR_STYLE, YAML_LN_BREAK, YAML_PLAIN_SCALAR_STYLE, YAML_SINGLE_QUOTED_SCALAR_STYLE, YAML_UTF8_ENCODING, }; -use core::ptr::{self}; unsafe fn FLUSH(emitter: &mut yaml_emitter_t) -> Result<(), ()> { if emitter.buffer.len() < OUTPUT_BUFFER_SIZE - 5 { @@ -82,6 +81,40 @@ unsafe fn WRITE_BREAK_CHAR(emitter: &mut yaml_emitter_t, ch: char) -> Result<(), Ok(()) } +#[derive(Default)] +struct Analysis<'a> { + pub anchor: Option>, + pub tag: Option>, + pub scalar: Option>, +} + +struct AnchorAnalysis<'a> { + pub anchor: &'a str, + pub alias: bool, +} + +struct TagAnalysis<'a> { + pub handle: &'a str, + pub suffix: &'a str, +} + +struct ScalarAnalysis<'a> { + /// The scalar value. + pub value: &'a str, + /// Does the scalar contain line breaks? + pub multiline: bool, + /// Can the scalar be expessed in the flow plain style? + pub flow_plain_allowed: bool, + /// Can the scalar be expressed in the block plain style? + pub block_plain_allowed: bool, + /// Can the scalar be expressed in the single quoted style? + pub single_quoted_allowed: bool, + /// Can the scalar be expressed in the literal or folded styles? + pub block_allowed: bool, + /// The output style. + pub style: yaml_scalar_style_t, +} + fn yaml_emitter_set_emitter_error( emitter: &mut yaml_emitter_t, problem: &'static str, @@ -103,9 +136,17 @@ pub unsafe fn yaml_emitter_emit( ) -> Result<(), ()> { emitter.events.push_back(event); while let Some(mut event) = yaml_emitter_needs_mode_events(emitter) { - yaml_emitter_analyze_event(emitter, &event)?; - yaml_emitter_state_machine(emitter, &event)?; + let tag_directives = core::mem::take(&mut emitter.tag_directives); + + let mut analysis = yaml_emitter_analyze_event(emitter, &event, &tag_directives)?; + yaml_emitter_state_machine(emitter, &event, &mut analysis)?; yaml_event_delete(&mut event); + + // The DOCUMENT-START event populates the tag directives, and this + // happens only once, so don't swap out the tags in that case. + if emitter.tag_directives.is_empty() { + emitter.tag_directives = tag_directives; + } } Ok(()) } @@ -180,6 +221,7 @@ unsafe fn yaml_emitter_increase_indent(emitter: &mut yaml_emitter_t, flow: bool, unsafe fn yaml_emitter_state_machine( emitter: &mut yaml_emitter_t, event: &yaml_event_t, + analysis: &mut Analysis, ) -> Result<(), ()> { match emitter.state { YAML_EMIT_STREAM_START_STATE => yaml_emitter_emit_stream_start(emitter, event), @@ -187,43 +229,45 @@ unsafe fn yaml_emitter_state_machine( yaml_emitter_emit_document_start(emitter, event, true) } YAML_EMIT_DOCUMENT_START_STATE => yaml_emitter_emit_document_start(emitter, event, false), - YAML_EMIT_DOCUMENT_CONTENT_STATE => yaml_emitter_emit_document_content(emitter, event), + YAML_EMIT_DOCUMENT_CONTENT_STATE => { + yaml_emitter_emit_document_content(emitter, event, analysis) + } YAML_EMIT_DOCUMENT_END_STATE => yaml_emitter_emit_document_end(emitter, event), YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE => { - yaml_emitter_emit_flow_sequence_item(emitter, event, true) + yaml_emitter_emit_flow_sequence_item(emitter, event, true, analysis) } YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE => { - yaml_emitter_emit_flow_sequence_item(emitter, event, false) + yaml_emitter_emit_flow_sequence_item(emitter, event, false, analysis) } YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE => { - yaml_emitter_emit_flow_mapping_key(emitter, event, true) + yaml_emitter_emit_flow_mapping_key(emitter, event, true, analysis) } YAML_EMIT_FLOW_MAPPING_KEY_STATE => { - yaml_emitter_emit_flow_mapping_key(emitter, event, false) + yaml_emitter_emit_flow_mapping_key(emitter, event, false, analysis) } YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE => { - yaml_emitter_emit_flow_mapping_value(emitter, event, true) + yaml_emitter_emit_flow_mapping_value(emitter, event, true, analysis) } YAML_EMIT_FLOW_MAPPING_VALUE_STATE => { - yaml_emitter_emit_flow_mapping_value(emitter, event, false) + yaml_emitter_emit_flow_mapping_value(emitter, event, false, analysis) } YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE => { - yaml_emitter_emit_block_sequence_item(emitter, event, true) + yaml_emitter_emit_block_sequence_item(emitter, event, true, analysis) } YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE => { - yaml_emitter_emit_block_sequence_item(emitter, event, false) + yaml_emitter_emit_block_sequence_item(emitter, event, false, analysis) } YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE => { - yaml_emitter_emit_block_mapping_key(emitter, event, true) + yaml_emitter_emit_block_mapping_key(emitter, event, true, analysis) } YAML_EMIT_BLOCK_MAPPING_KEY_STATE => { - yaml_emitter_emit_block_mapping_key(emitter, event, false) + yaml_emitter_emit_block_mapping_key(emitter, event, false, analysis) } YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE => { - yaml_emitter_emit_block_mapping_value(emitter, event, true) + yaml_emitter_emit_block_mapping_value(emitter, event, true, analysis) } YAML_EMIT_BLOCK_MAPPING_VALUE_STATE => { - yaml_emitter_emit_block_mapping_value(emitter, event, false) + yaml_emitter_emit_block_mapping_value(emitter, event, false, analysis) } YAML_EMIT_END_STATE => { yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END") @@ -362,9 +406,10 @@ unsafe fn yaml_emitter_emit_document_start( unsafe fn yaml_emitter_emit_document_content( emitter: &mut yaml_emitter_t, event: &yaml_event_t, + analysis: &mut Analysis, ) -> Result<(), ()> { emitter.states.push(YAML_EMIT_DOCUMENT_END_STATE); - yaml_emitter_emit_node(emitter, event, true, false, false, false) + yaml_emitter_emit_node(emitter, event, true, false, false, false, analysis) } unsafe fn yaml_emitter_emit_document_end( @@ -394,6 +439,7 @@ unsafe fn yaml_emitter_emit_flow_sequence_item( emitter: &mut yaml_emitter_t, event: &yaml_event_t, first: bool, + analysis: &mut Analysis, ) -> Result<(), ()> { if first { yaml_emitter_write_indicator(emitter, "[", true, true, false)?; @@ -418,13 +464,14 @@ unsafe fn yaml_emitter_emit_flow_sequence_item( yaml_emitter_write_indent(emitter)?; } emitter.states.push(YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE); - yaml_emitter_emit_node(emitter, event, false, true, false, false) + yaml_emitter_emit_node(emitter, event, false, true, false, false, analysis) } unsafe fn yaml_emitter_emit_flow_mapping_key( emitter: &mut yaml_emitter_t, event: &yaml_event_t, first: bool, + analysis: &mut Analysis, ) -> Result<(), ()> { if first { yaml_emitter_write_indicator(emitter, "{", true, true, false)?; @@ -451,15 +498,15 @@ unsafe fn yaml_emitter_emit_flow_mapping_key( if emitter.canonical || emitter.column > emitter.best_width { yaml_emitter_write_indent(emitter)?; } - if !emitter.canonical && yaml_emitter_check_simple_key(emitter, event) { + if !emitter.canonical && yaml_emitter_check_simple_key(emitter, event, analysis) { emitter .states .push(YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE); - yaml_emitter_emit_node(emitter, event, false, false, true, true) + yaml_emitter_emit_node(emitter, event, false, false, true, true, analysis) } else { yaml_emitter_write_indicator(emitter, "?", true, false, false)?; emitter.states.push(YAML_EMIT_FLOW_MAPPING_VALUE_STATE); - yaml_emitter_emit_node(emitter, event, false, false, true, false) + yaml_emitter_emit_node(emitter, event, false, false, true, false, analysis) } } @@ -467,6 +514,7 @@ unsafe fn yaml_emitter_emit_flow_mapping_value( emitter: &mut yaml_emitter_t, event: &yaml_event_t, simple: bool, + analysis: &mut Analysis, ) -> Result<(), ()> { if simple { yaml_emitter_write_indicator(emitter, ":", false, false, false)?; @@ -477,13 +525,14 @@ unsafe fn yaml_emitter_emit_flow_mapping_value( yaml_emitter_write_indicator(emitter, ":", true, false, false)?; } emitter.states.push(YAML_EMIT_FLOW_MAPPING_KEY_STATE); - yaml_emitter_emit_node(emitter, event, false, false, true, false) + yaml_emitter_emit_node(emitter, event, false, false, true, false, analysis) } unsafe fn yaml_emitter_emit_block_sequence_item( emitter: &mut yaml_emitter_t, event: &yaml_event_t, first: bool, + analysis: &mut Analysis, ) -> Result<(), ()> { if first { yaml_emitter_increase_indent( @@ -500,13 +549,14 @@ unsafe fn yaml_emitter_emit_block_sequence_item( yaml_emitter_write_indent(emitter)?; yaml_emitter_write_indicator(emitter, "-", true, false, true)?; emitter.states.push(YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE); - yaml_emitter_emit_node(emitter, event, false, true, false, false) + yaml_emitter_emit_node(emitter, event, false, true, false, false, analysis) } unsafe fn yaml_emitter_emit_block_mapping_key( emitter: &mut yaml_emitter_t, event: &yaml_event_t, first: bool, + analysis: &mut Analysis, ) -> Result<(), ()> { if first { yaml_emitter_increase_indent(emitter, false, false); @@ -517,15 +567,15 @@ unsafe fn yaml_emitter_emit_block_mapping_key( return Ok(()); } yaml_emitter_write_indent(emitter)?; - if yaml_emitter_check_simple_key(emitter, event) { + if yaml_emitter_check_simple_key(emitter, event, analysis) { emitter .states .push(YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE); - yaml_emitter_emit_node(emitter, event, false, false, true, true) + yaml_emitter_emit_node(emitter, event, false, false, true, true, analysis) } else { yaml_emitter_write_indicator(emitter, "?", true, false, true)?; emitter.states.push(YAML_EMIT_BLOCK_MAPPING_VALUE_STATE); - yaml_emitter_emit_node(emitter, event, false, false, true, false) + yaml_emitter_emit_node(emitter, event, false, false, true, false, analysis) } } @@ -533,6 +583,7 @@ unsafe fn yaml_emitter_emit_block_mapping_value( emitter: &mut yaml_emitter_t, event: &yaml_event_t, simple: bool, + analysis: &mut Analysis, ) -> Result<(), ()> { if simple { yaml_emitter_write_indicator(emitter, ":", false, false, false)?; @@ -541,7 +592,7 @@ unsafe fn yaml_emitter_emit_block_mapping_value( yaml_emitter_write_indicator(emitter, ":", true, false, true)?; } emitter.states.push(YAML_EMIT_BLOCK_MAPPING_KEY_STATE); - yaml_emitter_emit_node(emitter, event, false, false, true, false) + yaml_emitter_emit_node(emitter, event, false, false, true, false, analysis) } unsafe fn yaml_emitter_emit_node( @@ -551,6 +602,7 @@ unsafe fn yaml_emitter_emit_node( sequence: bool, mapping: bool, simple_key: bool, + analysis: &mut Analysis, ) -> Result<(), ()> { emitter.root_context = root; emitter.sequence_context = sequence; @@ -558,10 +610,14 @@ unsafe fn yaml_emitter_emit_node( emitter.simple_key_context = simple_key; match event.data { - YamlEventData::Alias { .. } => yaml_emitter_emit_alias(emitter, event), - YamlEventData::Scalar { .. } => yaml_emitter_emit_scalar(emitter, event), - YamlEventData::SequenceStart { .. } => yaml_emitter_emit_sequence_start(emitter, event), - YamlEventData::MappingStart { .. } => yaml_emitter_emit_mapping_start(emitter, event), + YamlEventData::Alias { .. } => yaml_emitter_emit_alias(emitter, event, &analysis.anchor), + YamlEventData::Scalar { .. } => yaml_emitter_emit_scalar(emitter, event, analysis), + YamlEventData::SequenceStart { .. } => { + yaml_emitter_emit_sequence_start(emitter, event, analysis) + } + YamlEventData::MappingStart { .. } => { + yaml_emitter_emit_mapping_start(emitter, event, analysis) + } _ => yaml_emitter_set_emitter_error( emitter, "expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS", @@ -572,8 +628,9 @@ unsafe fn yaml_emitter_emit_node( unsafe fn yaml_emitter_emit_alias( emitter: &mut yaml_emitter_t, _event: &yaml_event_t, + analysis: &Option, ) -> Result<(), ()> { - yaml_emitter_process_anchor(emitter)?; + yaml_emitter_process_anchor(emitter, analysis)?; if emitter.simple_key_context { PUT(emitter, b' ')?; } @@ -584,12 +641,22 @@ unsafe fn yaml_emitter_emit_alias( unsafe fn yaml_emitter_emit_scalar( emitter: &mut yaml_emitter_t, event: &yaml_event_t, + analysis: &mut Analysis, ) -> Result<(), ()> { - yaml_emitter_select_scalar_style(emitter, event)?; - yaml_emitter_process_anchor(emitter)?; - yaml_emitter_process_tag(emitter)?; + let Analysis { + anchor, + tag, + scalar: Some(scalar), + } = analysis + else { + unreachable!("no scalar analysis"); + }; + + yaml_emitter_select_scalar_style(emitter, event, scalar, tag)?; + yaml_emitter_process_anchor(emitter, anchor)?; + yaml_emitter_process_tag(emitter, tag)?; yaml_emitter_increase_indent(emitter, true, false); - yaml_emitter_process_scalar(emitter)?; + yaml_emitter_process_scalar(emitter, scalar)?; emitter.indent = emitter.indents.pop().unwrap(); emitter.state = emitter.states.pop().unwrap(); Ok(()) @@ -598,9 +665,11 @@ unsafe fn yaml_emitter_emit_scalar( unsafe fn yaml_emitter_emit_sequence_start( emitter: &mut yaml_emitter_t, event: &yaml_event_t, + analysis: &Analysis, ) -> Result<(), ()> { - yaml_emitter_process_anchor(emitter)?; - yaml_emitter_process_tag(emitter)?; + let Analysis { anchor, tag, .. } = analysis; + yaml_emitter_process_anchor(emitter, anchor)?; + yaml_emitter_process_tag(emitter, tag)?; let style = if let YamlEventData::SequenceStart { style, .. } = &event.data { *style @@ -623,9 +692,11 @@ unsafe fn yaml_emitter_emit_sequence_start( unsafe fn yaml_emitter_emit_mapping_start( emitter: &mut yaml_emitter_t, event: &yaml_event_t, + analysis: &Analysis, ) -> Result<(), ()> { - yaml_emitter_process_anchor(emitter)?; - yaml_emitter_process_tag(emitter)?; + let Analysis { anchor, tag, .. } = analysis; + yaml_emitter_process_anchor(emitter, anchor)?; + yaml_emitter_process_tag(emitter, tag)?; let style = if let YamlEventData::MappingStart { style, .. } = &event.data { *style @@ -649,10 +720,7 @@ unsafe fn yaml_emitter_check_empty_document(_emitter: &yaml_emitter_t) -> bool { false } -unsafe fn yaml_emitter_check_empty_sequence( - emitter: &yaml_emitter_t, - event: &yaml_event_t, -) -> bool { +fn yaml_emitter_check_empty_sequence(emitter: &yaml_emitter_t, event: &yaml_event_t) -> bool { if emitter.events.len() < 1 { return false; } @@ -669,7 +737,7 @@ unsafe fn yaml_emitter_check_empty_sequence( start && end } -unsafe fn yaml_emitter_check_empty_mapping(emitter: &yaml_emitter_t, event: &yaml_event_t) -> bool { +fn yaml_emitter_check_empty_mapping(emitter: &yaml_emitter_t, event: &yaml_event_t) -> bool { if emitter.events.len() < 1 { return false; } @@ -686,46 +754,55 @@ unsafe fn yaml_emitter_check_empty_mapping(emitter: &yaml_emitter_t, event: &yam start && end } -unsafe fn yaml_emitter_check_simple_key(emitter: &yaml_emitter_t, event: &yaml_event_t) -> bool { - let mut length: size_t = 0_u64; +fn yaml_emitter_check_simple_key( + emitter: &yaml_emitter_t, + event: &yaml_event_t, + analysis: &Analysis, +) -> bool { + let Analysis { + tag, + anchor, + scalar, + } = analysis; + + let mut length = anchor.as_ref().map(|a| a.anchor.len()).unwrap_or(0) + + tag + .as_ref() + .map(|t| t.handle.len() + t.suffix.len()) + .unwrap_or(0); match event.data { YamlEventData::Alias { .. } => { - length = - (length as libc::c_ulong).force_add(emitter.anchor_data.anchor_length) as size_t; + length = analysis + .anchor + .as_ref() + .map(|a| a.anchor.len()) + .unwrap_or(0); } YamlEventData::Scalar { .. } => { - if emitter.scalar_data.multiline { + let Some(scalar) = scalar else { + panic!("no analysis for scalar") + }; + + if scalar.multiline { return false; } - length = (length as libc::c_ulong) - .force_add(emitter.anchor_data.anchor_length) - .force_add(emitter.tag_data.handle_length) - .force_add(emitter.tag_data.suffix_length) - .force_add(emitter.scalar_data.length) as size_t; + length += scalar.value.len(); } YamlEventData::SequenceStart { .. } => { if !yaml_emitter_check_empty_sequence(emitter, event) { return false; } - length = (length as libc::c_ulong) - .force_add(emitter.anchor_data.anchor_length) - .force_add(emitter.tag_data.handle_length) - .force_add(emitter.tag_data.suffix_length) as size_t; } YamlEventData::MappingStart { .. } => { if !yaml_emitter_check_empty_mapping(emitter, event) { return false; } - length = (length as libc::c_ulong) - .force_add(emitter.anchor_data.anchor_length) - .force_add(emitter.tag_data.handle_length) - .force_add(emitter.tag_data.suffix_length) as size_t; } _ => return false, } - if length > 128_u64 { + if length > 128 { return false; } @@ -735,6 +812,8 @@ unsafe fn yaml_emitter_check_simple_key(emitter: &yaml_emitter_t, event: &yaml_e unsafe fn yaml_emitter_select_scalar_style( emitter: &mut yaml_emitter_t, event: &yaml_event_t, + scalar_analysis: &mut ScalarAnalysis, + tag_analysis: &mut Option, ) -> Result<(), ()> { if let YamlEventData::Scalar { plain_implicit, @@ -744,12 +823,12 @@ unsafe fn yaml_emitter_select_scalar_style( } = &event.data { let mut style: yaml_scalar_style_t = *style; - let no_tag = emitter.tag_data.handle.is_null() && emitter.tag_data.suffix.is_null(); + let no_tag = tag_analysis.is_none(); if no_tag && !*plain_implicit && !*quoted_implicit { - return yaml_emitter_set_emitter_error( + yaml_emitter_set_emitter_error( emitter, "neither tag nor implicit flags are specified", - ); + )?; } if style == YAML_ANY_SCALAR_STYLE { style = YAML_PLAIN_SCALAR_STYLE; @@ -757,16 +836,16 @@ unsafe fn yaml_emitter_select_scalar_style( if emitter.canonical { style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; } - if emitter.simple_key_context && emitter.scalar_data.multiline { + if emitter.simple_key_context && scalar_analysis.multiline { style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; } if style == YAML_PLAIN_SCALAR_STYLE { - if emitter.flow_level != 0 && !emitter.scalar_data.flow_plain_allowed - || emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed + if emitter.flow_level != 0 && !scalar_analysis.flow_plain_allowed + || emitter.flow_level == 0 && !scalar_analysis.block_plain_allowed { style = YAML_SINGLE_QUOTED_SCALAR_STYLE; } - if emitter.scalar_data.length == 0 + if scalar_analysis.value.is_empty() && (emitter.flow_level != 0 || emitter.simple_key_context) { style = YAML_SINGLE_QUOTED_SCALAR_STYLE; @@ -776,12 +855,12 @@ unsafe fn yaml_emitter_select_scalar_style( } } if style == YAML_SINGLE_QUOTED_SCALAR_STYLE { - if !emitter.scalar_data.single_quoted_allowed { + if !scalar_analysis.single_quoted_allowed { style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; } } if style == YAML_LITERAL_SCALAR_STYLE || style == YAML_FOLDED_SCALAR_STYLE { - if !emitter.scalar_data.block_allowed + if !scalar_analysis.block_allowed || emitter.flow_level != 0 || emitter.simple_key_context { @@ -789,123 +868,90 @@ unsafe fn yaml_emitter_select_scalar_style( } } if no_tag && !*quoted_implicit && style != YAML_PLAIN_SCALAR_STYLE { - emitter.tag_data.handle = - b"!\0" as *const u8 as *const libc::c_char as *mut yaml_char_t; - emitter.tag_data.handle_length = 1_u64; + *tag_analysis = Some(TagAnalysis { + handle: "!", + suffix: "", + }); } - emitter.scalar_data.style = style; + scalar_analysis.style = style; Ok(()) } else { unreachable!() } } -unsafe fn yaml_emitter_process_anchor(emitter: &mut yaml_emitter_t) -> Result<(), ()> { - if emitter.anchor_data.anchor.is_null() { +unsafe fn yaml_emitter_process_anchor( + emitter: &mut yaml_emitter_t, + analysis: &Option, +) -> Result<(), ()> { + let Some(analysis) = analysis.as_ref() else { return Ok(()); - } + }; yaml_emitter_write_indicator( emitter, - if emitter.anchor_data.alias { "*" } else { "&" }, + if analysis.alias { "*" } else { "&" }, true, false, false, )?; - yaml_emitter_write_anchor( - emitter, - core::str::from_utf8_unchecked(core::slice::from_raw_parts( - emitter.anchor_data.anchor, - emitter.anchor_data.anchor_length as _, - )), - ) + yaml_emitter_write_anchor(emitter, analysis.anchor) } -unsafe fn yaml_emitter_process_tag(emitter: &mut yaml_emitter_t) -> Result<(), ()> { - if emitter.tag_data.handle.is_null() && emitter.tag_data.suffix.is_null() { +unsafe fn yaml_emitter_process_tag( + emitter: &mut yaml_emitter_t, + analysis: &Option, +) -> Result<(), ()> { + let Some(analysis) = analysis.as_ref() else { + return Ok(()); + }; + + if analysis.handle.is_empty() && analysis.suffix.is_empty() { return Ok(()); } - if !emitter.tag_data.handle.is_null() { - yaml_emitter_write_tag_handle( - emitter, - core::str::from_utf8_unchecked(core::slice::from_raw_parts( - emitter.tag_data.handle, - emitter.tag_data.handle_length as _, - )), - )?; - if !emitter.tag_data.suffix.is_null() { - yaml_emitter_write_tag_content( - emitter, - core::str::from_utf8_unchecked(core::slice::from_raw_parts( - emitter.tag_data.suffix, - emitter.tag_data.suffix_length as _, - )), - false, - )?; + if !analysis.handle.is_empty() { + yaml_emitter_write_tag_handle(emitter, analysis.handle)?; + if !analysis.suffix.is_empty() { + yaml_emitter_write_tag_content(emitter, analysis.suffix, false)?; } } else { yaml_emitter_write_indicator(emitter, "!<", true, false, false)?; - yaml_emitter_write_tag_content( - emitter, - core::str::from_utf8_unchecked(core::slice::from_raw_parts( - emitter.tag_data.suffix, - emitter.tag_data.suffix_length as _, - )), - false, - )?; + yaml_emitter_write_tag_content(emitter, analysis.suffix, false)?; yaml_emitter_write_indicator(emitter, ">", false, false, false)?; } Ok(()) } -unsafe fn yaml_emitter_process_scalar(emitter: &mut yaml_emitter_t) -> Result<(), ()> { - match emitter.scalar_data.style { +unsafe fn yaml_emitter_process_scalar( + emitter: &mut yaml_emitter_t, + analysis: &ScalarAnalysis, +) -> Result<(), ()> { + match analysis.style { YAML_PLAIN_SCALAR_STYLE => { return yaml_emitter_write_plain_scalar( emitter, - core::str::from_utf8_unchecked(core::slice::from_raw_parts( - emitter.scalar_data.value, - emitter.scalar_data.length as _, - )), + analysis.value, !emitter.simple_key_context, ); } YAML_SINGLE_QUOTED_SCALAR_STYLE => { return yaml_emitter_write_single_quoted_scalar( emitter, - core::str::from_utf8_unchecked(core::slice::from_raw_parts( - emitter.scalar_data.value, - emitter.scalar_data.length as _, - )), + analysis.value, !emitter.simple_key_context, ); } YAML_DOUBLE_QUOTED_SCALAR_STYLE => { return yaml_emitter_write_double_quoted_scalar( emitter, - core::str::from_utf8_unchecked(core::slice::from_raw_parts( - emitter.scalar_data.value, - emitter.scalar_data.length as _, - )), + analysis.value, !emitter.simple_key_context, ); } YAML_LITERAL_SCALAR_STYLE => { - return yaml_emitter_write_literal_scalar( - emitter, - core::str::from_utf8_unchecked(core::slice::from_raw_parts( - emitter.scalar_data.value, - emitter.scalar_data.length as _, - )), - ); + return yaml_emitter_write_literal_scalar(emitter, analysis.value); } YAML_FOLDED_SCALAR_STYLE => { - return yaml_emitter_write_folded_scalar( - emitter, - core::str::from_utf8_unchecked(core::slice::from_raw_parts( - emitter.scalar_data.value, - emitter.scalar_data.length as _, - )), - ); + return yaml_emitter_write_folded_scalar(emitter, analysis.value); } _ => {} } @@ -955,63 +1001,66 @@ unsafe fn yaml_emitter_analyze_tag_directive( Ok(()) } -unsafe fn yaml_emitter_analyze_anchor( +fn yaml_emitter_analyze_anchor<'a>( emitter: &mut yaml_emitter_t, - anchor: &str, + anchor: &'a str, alias: bool, -) -> Result<(), ()> { +) -> Result, ()> { if anchor.is_empty() { - return yaml_emitter_set_emitter_error( + yaml_emitter_set_emitter_error( emitter, if alias { "alias value must not be empty" } else { "anchor value must not be empty" }, - ); + )?; } for ch in anchor.chars() { if !IS_ALPHA_CHAR!(ch) { - return yaml_emitter_set_emitter_error( + yaml_emitter_set_emitter_error( emitter, if alias { "alias value must contain alphanumerical characters only" } else { "anchor value must contain alphanumerical characters only" }, - ); + )?; } } - emitter.anchor_data.anchor = anchor.as_ptr(); - emitter.anchor_data.anchor_length = anchor.len() as _; - emitter.anchor_data.alias = alias; - Ok(()) + Ok(AnchorAnalysis { anchor, alias }) } -unsafe fn yaml_emitter_analyze_tag(emitter: &mut yaml_emitter_t, tag: &str) -> Result<(), ()> { +fn yaml_emitter_analyze_tag<'a>( + emitter: &mut yaml_emitter_t, + tag: &'a str, + tag_directives: &'a [yaml_tag_directive_t], +) -> Result, ()> { if tag.is_empty() { - return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty"); + yaml_emitter_set_emitter_error(emitter, "tag value must not be empty")?; } - for tag_directive in emitter.tag_directives.iter() { + let mut handle = ""; + let mut suffix = tag; + + for tag_directive in tag_directives.iter() { let prefix_len = tag_directive.prefix.len(); if prefix_len < tag.len() && tag_directive.prefix == tag[0..prefix_len] { - emitter.tag_data.handle = tag_directive.handle.as_ptr(); - emitter.tag_data.handle_length = tag_directive.handle.len() as _; - let suffix = &tag[prefix_len..]; - emitter.tag_data.suffix = suffix.as_ptr(); - emitter.tag_data.suffix_length = suffix.len() as _; - return Ok(()); + handle = &tag_directive.handle; + suffix = &tag[prefix_len..]; + break; } } - emitter.tag_data.suffix = tag.as_ptr(); - emitter.tag_data.suffix_length = tag.len() as _; - Ok(()) + + Ok(TagAnalysis { handle, suffix }) } -unsafe fn yaml_emitter_analyze_scalar(emitter: &mut yaml_emitter_t, value: &str) -> Result<(), ()> { +fn yaml_emitter_analyze_scalar<'a>( + emitter: &mut yaml_emitter_t, + value: &'a str, +) -> Result, ()> { let mut block_indicators = false; let mut flow_indicators = false; let mut line_breaks = false; @@ -1026,16 +1075,16 @@ unsafe fn yaml_emitter_analyze_scalar(emitter: &mut yaml_emitter_t, value: &str) let mut previous_space = false; let mut previous_break = false; - emitter.scalar_data.value = value.as_ptr(); - emitter.scalar_data.length = value.len() as _; - if value.is_empty() { - emitter.scalar_data.multiline = false; - emitter.scalar_data.flow_plain_allowed = false; - emitter.scalar_data.block_plain_allowed = true; - emitter.scalar_data.single_quoted_allowed = true; - emitter.scalar_data.block_allowed = false; - return Ok(()); + return Ok(ScalarAnalysis { + value: "", + multiline: false, + flow_plain_allowed: false, + block_plain_allowed: true, + single_quoted_allowed: true, + block_allowed: false, + style: YAML_ANY_SCALAR_STYLE, + }); } if value.starts_with("---") || value.starts_with("...") { @@ -1128,57 +1177,63 @@ unsafe fn yaml_emitter_analyze_scalar(emitter: &mut yaml_emitter_t, value: &str) first = false; } - emitter.scalar_data.multiline = line_breaks; - emitter.scalar_data.flow_plain_allowed = true; - emitter.scalar_data.block_plain_allowed = true; - emitter.scalar_data.single_quoted_allowed = true; - emitter.scalar_data.block_allowed = true; + let mut analysis = ScalarAnalysis { + value, + multiline: line_breaks, + flow_plain_allowed: true, + block_plain_allowed: true, + single_quoted_allowed: true, + block_allowed: true, + style: YAML_ANY_SCALAR_STYLE, + }; + + analysis.multiline = line_breaks; + analysis.flow_plain_allowed = true; + analysis.block_plain_allowed = true; + analysis.single_quoted_allowed = true; + analysis.block_allowed = true; if leading_space || leading_break || trailing_space || trailing_break { - emitter.scalar_data.flow_plain_allowed = false; - emitter.scalar_data.block_plain_allowed = false; + analysis.flow_plain_allowed = false; + analysis.block_plain_allowed = false; } if trailing_space { - emitter.scalar_data.block_allowed = false; + analysis.block_allowed = false; } if break_space { - emitter.scalar_data.flow_plain_allowed = false; - emitter.scalar_data.block_plain_allowed = false; - emitter.scalar_data.single_quoted_allowed = false; + analysis.flow_plain_allowed = false; + analysis.block_plain_allowed = false; + analysis.single_quoted_allowed = false; } if space_break || special_characters { - emitter.scalar_data.flow_plain_allowed = false; - emitter.scalar_data.block_plain_allowed = false; - emitter.scalar_data.single_quoted_allowed = false; - emitter.scalar_data.block_allowed = false; + analysis.flow_plain_allowed = false; + analysis.block_plain_allowed = false; + analysis.single_quoted_allowed = false; + analysis.block_allowed = false; } if line_breaks { - emitter.scalar_data.flow_plain_allowed = false; - emitter.scalar_data.block_plain_allowed = false; + analysis.flow_plain_allowed = false; + analysis.block_plain_allowed = false; } if flow_indicators { - emitter.scalar_data.flow_plain_allowed = false; + analysis.flow_plain_allowed = false; } if block_indicators { - emitter.scalar_data.block_plain_allowed = false; + analysis.block_plain_allowed = false; } - Ok(()) + Ok(analysis) } -unsafe fn yaml_emitter_analyze_event( +fn yaml_emitter_analyze_event<'a>( emitter: &mut yaml_emitter_t, - event: &yaml_event_t, -) -> Result<(), ()> { - emitter.anchor_data.anchor = ptr::null_mut::(); - emitter.anchor_data.anchor_length = 0_u64; - emitter.tag_data.handle = ptr::null_mut::(); - emitter.tag_data.handle_length = 0_u64; - emitter.tag_data.suffix = ptr::null_mut::(); - emitter.tag_data.suffix_length = 0_u64; - emitter.scalar_data.value = ptr::null_mut::(); - emitter.scalar_data.length = 0_u64; + event: &'a yaml_event_t, + tag_directives: &'a [yaml_tag_directive_t], +) -> Result, ()> { + let mut analysis = Analysis::default(); match &event.data { - YamlEventData::Alias { anchor } => yaml_emitter_analyze_anchor(emitter, anchor, true), + YamlEventData::Alias { anchor } => { + analysis.anchor = Some(yaml_emitter_analyze_anchor(emitter, anchor, true)?); + } YamlEventData::Scalar { anchor, tag, @@ -1189,12 +1244,16 @@ unsafe fn yaml_emitter_analyze_event( } => { let (plain_implicit, quoted_implicit) = (*plain_implicit, *quoted_implicit); if let Some(anchor) = anchor { - yaml_emitter_analyze_anchor(emitter, anchor, false)?; + analysis.anchor = Some(yaml_emitter_analyze_anchor(emitter, anchor, false)?); } if tag.is_some() && (emitter.canonical || !plain_implicit && !quoted_implicit) { - yaml_emitter_analyze_tag(emitter, tag.as_deref().unwrap())?; + analysis.tag = Some(yaml_emitter_analyze_tag( + emitter, + tag.as_deref().unwrap(), + tag_directives, + )?); } - yaml_emitter_analyze_scalar(emitter, value) + analysis.scalar = Some(yaml_emitter_analyze_scalar(emitter, value)?); } YamlEventData::SequenceStart { anchor, @@ -1203,12 +1262,15 @@ unsafe fn yaml_emitter_analyze_event( .. } => { if let Some(anchor) = anchor { - yaml_emitter_analyze_anchor(emitter, anchor, false)?; + analysis.anchor = Some(yaml_emitter_analyze_anchor(emitter, anchor, false)?); } if tag.is_some() && (emitter.canonical || !*implicit) { - yaml_emitter_analyze_tag(emitter, tag.as_deref().unwrap())?; + analysis.tag = Some(yaml_emitter_analyze_tag( + emitter, + tag.as_deref().unwrap(), + tag_directives, + )?); } - Ok(()) } YamlEventData::MappingStart { anchor, @@ -1217,15 +1279,20 @@ unsafe fn yaml_emitter_analyze_event( .. } => { if let Some(anchor) = anchor { - yaml_emitter_analyze_anchor(emitter, anchor, false)?; + analysis.anchor = Some(yaml_emitter_analyze_anchor(emitter, anchor, false)?); } if tag.is_some() && (emitter.canonical || !*implicit) { - yaml_emitter_analyze_tag(emitter, tag.as_deref().unwrap())?; + analysis.tag = Some(yaml_emitter_analyze_tag( + emitter, + tag.as_deref().unwrap(), + tag_directives, + )?); } - Ok(()) } - _ => Ok(()), + _ => {} } + + Ok(analysis) } unsafe fn yaml_emitter_write_bom(emitter: &mut yaml_emitter_t) -> Result<(), ()> { diff --git a/src/lib.rs b/src/lib.rs index 9f9f794..d9977fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,7 +47,7 @@ use core::mem::size_of; mod libc { pub use core::ffi::c_void; pub use core::primitive::{ - i32 as c_int, i64 as c_long, i8 as c_char, u32 as c_uint, u64 as c_ulong, u8 as c_uchar, + i32 as c_int, i64 as c_long, u32 as c_uint, u64 as c_ulong, u8 as c_uchar, }; } diff --git a/src/yaml.rs b/src/yaml.rs index b7f7e1a..c75ed17 100644 --- a/src/yaml.rs +++ b/src/yaml.rs @@ -6,7 +6,7 @@ use crate::libc; use core::ptr; pub use self::yaml_encoding_t::*; -pub use core::primitive::{i64 as ptrdiff_t, u64 as size_t, u8 as yaml_char_t}; +pub use core::primitive::{i64 as ptrdiff_t, u64 as size_t}; /// The version directive data. #[derive(Clone, Copy, Debug)] @@ -936,12 +936,6 @@ pub struct yaml_emitter_t { pub(crate) indention: bool, /// If an explicit document end is required? pub(crate) open_ended: libc::c_int, - /// Anchor analysis. - pub(crate) anchor_data: unnamed_yaml_emitter_t_anchor_data, - /// Tag analysis. - pub(crate) tag_data: unnamed_yaml_emitter_t_tag_data, - /// Scalar analysis. - pub(crate) scalar_data: unnamed_yaml_emitter_t_scalar_data, /// If the stream was already opened? pub(crate) opened: bool, /// If the stream was already closed? @@ -985,9 +979,6 @@ impl Default for yaml_emitter_t { whitespace: Default::default(), indention: Default::default(), open_ended: Default::default(), - anchor_data: Default::default(), - tag_data: Default::default(), - scalar_data: Default::default(), opened: Default::default(), closed: Default::default(), anchors: Default::default(), @@ -1015,81 +1006,3 @@ impl Default for unnamed_yaml_emitter_t_output_string { } } } - -#[repr(C)] -pub(crate) struct unnamed_yaml_emitter_t_anchor_data { - /// The anchor value. - pub anchor: *const yaml_char_t, - /// The anchor length. - pub anchor_length: size_t, - /// Is it an alias? - pub alias: bool, -} - -impl Default for unnamed_yaml_emitter_t_anchor_data { - fn default() -> Self { - Self { - anchor: ptr::null_mut(), - anchor_length: 0, - alias: false, - } - } -} - -#[repr(C)] -pub(crate) struct unnamed_yaml_emitter_t_tag_data { - /// The tag handle. - pub handle: *const yaml_char_t, - /// The tag handle length. - pub handle_length: size_t, - /// The tag suffix. - pub suffix: *const yaml_char_t, - /// The tag suffix length. - pub suffix_length: size_t, -} - -impl Default for unnamed_yaml_emitter_t_tag_data { - fn default() -> Self { - Self { - handle: ptr::null_mut(), - handle_length: 0, - suffix: ptr::null_mut(), - suffix_length: 0, - } - } -} - -#[repr(C)] -pub(crate) struct unnamed_yaml_emitter_t_scalar_data { - /// The scalar value. - pub value: *const yaml_char_t, - /// The scalar length. - pub length: size_t, - /// Does the scalar contain line breaks? - pub multiline: bool, - /// Can the scalar be expessed in the flow plain style? - pub flow_plain_allowed: bool, - /// Can the scalar be expressed in the block plain style? - pub block_plain_allowed: bool, - /// Can the scalar be expressed in the single quoted style? - pub single_quoted_allowed: bool, - /// Can the scalar be expressed in the literal or folded styles? - pub block_allowed: bool, - /// The output style. - pub style: yaml_scalar_style_t, -} - -impl Default for unnamed_yaml_emitter_t_scalar_data { - fn default() -> Self { - Self { - value: ptr::null_mut(), - length: 0, - multiline: false, - flow_plain_allowed: false, - block_plain_allowed: false, - single_quoted_allowed: false, - block_allowed: false, - style: Default::default(), - } - } -}