wrap unsafe portion of Emitter into @trusted helper functions
This commit is contained in:
parent
aa1af974e8
commit
4cb78ff6f5
|
@ -83,9 +83,10 @@ struct Emitter
|
||||||
Encoding encoding_ = Encoding.UTF_8;
|
Encoding encoding_ = Encoding.UTF_8;
|
||||||
|
|
||||||
///Stack of states.
|
///Stack of states.
|
||||||
Array!(void delegate()) states_;
|
Array!(void function() @safe) states_;
|
||||||
///Current state.
|
///Current state.
|
||||||
void delegate() state_;
|
//WARNING! DO NOT CALL DIRECTLY! Use callNext() instead!
|
||||||
|
void function() @safe state_;
|
||||||
|
|
||||||
///Event queue.
|
///Event queue.
|
||||||
Queue!Event events_;
|
Queue!Event events_;
|
||||||
|
@ -174,7 +175,7 @@ struct Emitter
|
||||||
indents_.reserve(32);
|
indents_.reserve(32);
|
||||||
stream_ = stream;
|
stream_ = stream;
|
||||||
canonical_ = canonical;
|
canonical_ = canonical;
|
||||||
state_ = &expectStreamStart;
|
nextExpected(&expectStreamStart);
|
||||||
|
|
||||||
if(indent > 1 && indent < 10){bestIndent_ = indent;}
|
if(indent > 1 && indent < 10){bestIndent_ = indent;}
|
||||||
if(width > bestIndent_ * 2) {bestWidth_ = width;}
|
if(width > bestIndent_ * 2) {bestWidth_ = width;}
|
||||||
|
@ -184,23 +185,20 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Emit an event. Throws EmitterException on error.
|
///Emit an event. Throws EmitterException on error.
|
||||||
void emit(Event event) @trusted
|
void emit(Event event) @safe
|
||||||
{
|
{
|
||||||
events_.push(event);
|
events_.push(event);
|
||||||
while(!needMoreEvents())
|
while(!needMoreEvents())
|
||||||
{
|
{
|
||||||
event_ = events_.pop();
|
event_ = events_.pop();
|
||||||
// copy construction and move semantic can
|
callNext();
|
||||||
// exceptionally lead to wrong delegate context.
|
|
||||||
state_.ptr = &this;
|
|
||||||
state_();
|
|
||||||
event_.destroy();
|
event_.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///Pop and return the newest state in states_.
|
///Pop and return the newest state in states_.
|
||||||
void delegate() popState() @trusted
|
void function() @safe popState() @trusted
|
||||||
{
|
{
|
||||||
enforce(states_.length > 0,
|
enforce(states_.length > 0,
|
||||||
new YAMLException("Emitter: Need to pop a state but there are no states left"));
|
new YAMLException("Emitter: Need to pop a state but there are no states left"));
|
||||||
|
@ -209,6 +207,11 @@ struct Emitter
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pushState(void delegate() @safe func) @trusted
|
||||||
|
{
|
||||||
|
states_ ~= func.funcptr;
|
||||||
|
}
|
||||||
|
|
||||||
///Pop and return the newest indent in indents_.
|
///Pop and return the newest indent in indents_.
|
||||||
int popIndent() @trusted
|
int popIndent() @trusted
|
||||||
{
|
{
|
||||||
|
@ -313,14 +316,14 @@ struct Emitter
|
||||||
//Stream handlers.
|
//Stream handlers.
|
||||||
|
|
||||||
///Handle start of a file/stream.
|
///Handle start of a file/stream.
|
||||||
void expectStreamStart() @trusted
|
void expectStreamStart() @safe
|
||||||
{
|
{
|
||||||
enforce(eventTypeIs(EventID.StreamStart),
|
enforce(eventTypeIs(EventID.StreamStart),
|
||||||
new EmitterException("Expected YStreamStart, but got " ~ event_.idString));
|
new EmitterException("Expected YStreamStart, but got " ~ event_.idString));
|
||||||
|
|
||||||
encoding_ = event_.encoding;
|
encoding_ = event_.encoding;
|
||||||
writeStreamStart();
|
writeStreamStart();
|
||||||
state_ = &expectDocumentStart!(Yes.first);
|
nextExpected(&expectDocumentStart!(Yes.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
///Expect nothing, throwing if we still have something.
|
///Expect nothing, throwing if we still have something.
|
||||||
|
@ -332,7 +335,7 @@ struct Emitter
|
||||||
//Document handlers.
|
//Document handlers.
|
||||||
|
|
||||||
///Handle start of a document.
|
///Handle start of a document.
|
||||||
void expectDocumentStart(Flag!"first" first)() @trusted
|
void expectDocumentStart(Flag!"first" first)() @safe
|
||||||
{
|
{
|
||||||
enforce(eventTypeIs(EventID.DocumentStart) || eventTypeIs(EventID.StreamEnd),
|
enforce(eventTypeIs(EventID.DocumentStart) || eventTypeIs(EventID.StreamEnd),
|
||||||
new EmitterException("Expected DocumentStart or YStreamEnd, but got "
|
new EmitterException("Expected DocumentStart or YStreamEnd, but got "
|
||||||
|
@ -384,7 +387,7 @@ struct Emitter
|
||||||
writeIndicator("---", Yes.needWhitespace);
|
writeIndicator("---", Yes.needWhitespace);
|
||||||
if(canonical_){writeIndent();}
|
if(canonical_){writeIndent();}
|
||||||
}
|
}
|
||||||
state_ = &expectRootNode;
|
nextExpected(&expectRootNode);
|
||||||
}
|
}
|
||||||
else if(event_.id == EventID.StreamEnd)
|
else if(event_.id == EventID.StreamEnd)
|
||||||
{
|
{
|
||||||
|
@ -394,12 +397,12 @@ struct Emitter
|
||||||
writeIndent();
|
writeIndent();
|
||||||
}
|
}
|
||||||
writeStreamEnd();
|
writeStreamEnd();
|
||||||
state_ = &expectNothing;
|
nextExpected(&expectNothing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle end of a document.
|
///Handle end of a document.
|
||||||
void expectDocumentEnd() @trusted
|
void expectDocumentEnd() @safe
|
||||||
{
|
{
|
||||||
enforce(eventTypeIs(EventID.DocumentEnd),
|
enforce(eventTypeIs(EventID.DocumentEnd),
|
||||||
new EmitterException("Expected DocumentEnd, but got " ~ event_.idString));
|
new EmitterException("Expected DocumentEnd, but got " ~ event_.idString));
|
||||||
|
@ -411,26 +414,26 @@ struct Emitter
|
||||||
writeIndent();
|
writeIndent();
|
||||||
}
|
}
|
||||||
stream_.flush();
|
stream_.flush();
|
||||||
state_ = &expectDocumentStart!(No.first);
|
nextExpected(&expectDocumentStart!(No.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle the root node of a document.
|
///Handle the root node of a document.
|
||||||
void expectRootNode() @trusted
|
void expectRootNode() @safe
|
||||||
{
|
{
|
||||||
states_ ~= &expectDocumentEnd;
|
pushState(&expectDocumentEnd);
|
||||||
expectNode(Context.Root);
|
expectNode(Context.Root);
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle a mapping node.
|
///Handle a mapping node.
|
||||||
//
|
//
|
||||||
//Params: simpleKey = Are we in a simple key?
|
//Params: simpleKey = Are we in a simple key?
|
||||||
void expectMappingNode(const bool simpleKey = false)
|
void expectMappingNode(const bool simpleKey = false) @safe
|
||||||
{
|
{
|
||||||
expectNode(simpleKey ? Context.MappingSimpleKey : Context.MappingNoSimpleKey);
|
expectNode(simpleKey ? Context.MappingSimpleKey : Context.MappingNoSimpleKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle a sequence node.
|
///Handle a sequence node.
|
||||||
void expectSequenceNode()
|
void expectSequenceNode() @safe
|
||||||
{
|
{
|
||||||
expectNode(Context.Sequence);
|
expectNode(Context.Sequence);
|
||||||
}
|
}
|
||||||
|
@ -484,7 +487,7 @@ struct Emitter
|
||||||
{
|
{
|
||||||
enforce(event_.anchor !is null, new EmitterException("Anchor is not specified for alias"));
|
enforce(event_.anchor !is null, new EmitterException("Anchor is not specified for alias"));
|
||||||
processAnchor("*");
|
processAnchor("*");
|
||||||
state_ = popState();
|
nextExpected(popState());
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle a scalar.
|
///Handle a scalar.
|
||||||
|
@ -493,22 +496,22 @@ struct Emitter
|
||||||
increaseIndent(Yes.flow);
|
increaseIndent(Yes.flow);
|
||||||
processScalar();
|
processScalar();
|
||||||
indent_ = popIndent();
|
indent_ = popIndent();
|
||||||
state_ = popState();
|
nextExpected(popState());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Flow sequence handlers.
|
//Flow sequence handlers.
|
||||||
|
|
||||||
///Handle a flow sequence.
|
///Handle a flow sequence.
|
||||||
void expectFlowSequence() @trusted
|
void expectFlowSequence() @safe
|
||||||
{
|
{
|
||||||
writeIndicator("[", Yes.needWhitespace, Yes.whitespace);
|
writeIndicator("[", Yes.needWhitespace, Yes.whitespace);
|
||||||
++flowLevel_;
|
++flowLevel_;
|
||||||
increaseIndent(Yes.flow);
|
increaseIndent(Yes.flow);
|
||||||
state_ = &expectFlowSequenceItem!(Yes.first);
|
nextExpected(&expectFlowSequenceItem!(Yes.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle a flow sequence item.
|
///Handle a flow sequence item.
|
||||||
void expectFlowSequenceItem(Flag!"first" first)() @trusted
|
void expectFlowSequenceItem(Flag!"first" first)() @safe
|
||||||
{
|
{
|
||||||
if(event_.id == EventID.SequenceEnd)
|
if(event_.id == EventID.SequenceEnd)
|
||||||
{
|
{
|
||||||
|
@ -520,28 +523,28 @@ struct Emitter
|
||||||
writeIndent();
|
writeIndent();
|
||||||
}
|
}
|
||||||
writeIndicator("]", No.needWhitespace);
|
writeIndicator("]", No.needWhitespace);
|
||||||
state_ = popState();
|
nextExpected(popState());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
static if(!first){writeIndicator(",", No.needWhitespace);}
|
static if(!first){writeIndicator(",", No.needWhitespace);}
|
||||||
if(canonical_ || column_ > bestWidth_){writeIndent();}
|
if(canonical_ || column_ > bestWidth_){writeIndent();}
|
||||||
states_ ~= &expectFlowSequenceItem!(No.first);
|
pushState(&expectFlowSequenceItem!(No.first));
|
||||||
expectSequenceNode();
|
expectSequenceNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Flow mapping handlers.
|
//Flow mapping handlers.
|
||||||
|
|
||||||
///Handle a flow mapping.
|
///Handle a flow mapping.
|
||||||
void expectFlowMapping() @trusted
|
void expectFlowMapping() @safe
|
||||||
{
|
{
|
||||||
writeIndicator("{", Yes.needWhitespace, Yes.whitespace);
|
writeIndicator("{", Yes.needWhitespace, Yes.whitespace);
|
||||||
++flowLevel_;
|
++flowLevel_;
|
||||||
increaseIndent(Yes.flow);
|
increaseIndent(Yes.flow);
|
||||||
state_ = &expectFlowMappingKey!(Yes.first);
|
nextExpected(&expectFlowMappingKey!(Yes.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle a key in a flow mapping.
|
///Handle a key in a flow mapping.
|
||||||
void expectFlowMappingKey(Flag!"first" first)() @trusted
|
void expectFlowMappingKey(Flag!"first" first)() @safe
|
||||||
{
|
{
|
||||||
if(event_.id == EventID.MappingEnd)
|
if(event_.id == EventID.MappingEnd)
|
||||||
{
|
{
|
||||||
|
@ -553,7 +556,7 @@ struct Emitter
|
||||||
writeIndent();
|
writeIndent();
|
||||||
}
|
}
|
||||||
writeIndicator("}", No.needWhitespace);
|
writeIndicator("}", No.needWhitespace);
|
||||||
state_ = popState();
|
nextExpected(popState());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,120 +564,120 @@ struct Emitter
|
||||||
if(canonical_ || column_ > bestWidth_){writeIndent();}
|
if(canonical_ || column_ > bestWidth_){writeIndent();}
|
||||||
if(!canonical_ && checkSimpleKey())
|
if(!canonical_ && checkSimpleKey())
|
||||||
{
|
{
|
||||||
states_ ~= &expectFlowMappingSimpleValue;
|
pushState(&expectFlowMappingSimpleValue);
|
||||||
expectMappingNode(true);
|
expectMappingNode(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeIndicator("?", Yes.needWhitespace);
|
writeIndicator("?", Yes.needWhitespace);
|
||||||
states_ ~= &expectFlowMappingValue;
|
pushState(&expectFlowMappingValue);
|
||||||
expectMappingNode();
|
expectMappingNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle a simple value in a flow mapping.
|
///Handle a simple value in a flow mapping.
|
||||||
void expectFlowMappingSimpleValue() @trusted
|
void expectFlowMappingSimpleValue() @safe
|
||||||
{
|
{
|
||||||
writeIndicator(":", No.needWhitespace);
|
writeIndicator(":", No.needWhitespace);
|
||||||
states_ ~= &expectFlowMappingKey!(No.first);
|
pushState(&expectFlowMappingKey!(No.first));
|
||||||
expectMappingNode();
|
expectMappingNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle a complex value in a flow mapping.
|
///Handle a complex value in a flow mapping.
|
||||||
void expectFlowMappingValue() @trusted
|
void expectFlowMappingValue() @safe
|
||||||
{
|
{
|
||||||
if(canonical_ || column_ > bestWidth_){writeIndent();}
|
if(canonical_ || column_ > bestWidth_){writeIndent();}
|
||||||
writeIndicator(":", Yes.needWhitespace);
|
writeIndicator(":", Yes.needWhitespace);
|
||||||
states_ ~= &expectFlowMappingKey!(No.first);
|
pushState(&expectFlowMappingKey!(No.first));
|
||||||
expectMappingNode();
|
expectMappingNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Block sequence handlers.
|
//Block sequence handlers.
|
||||||
|
|
||||||
///Handle a block sequence.
|
///Handle a block sequence.
|
||||||
void expectBlockSequence() @trusted
|
void expectBlockSequence() @safe
|
||||||
{
|
{
|
||||||
const indentless = (context_ == Context.MappingNoSimpleKey ||
|
const indentless = (context_ == Context.MappingNoSimpleKey ||
|
||||||
context_ == Context.MappingSimpleKey) && !indentation_;
|
context_ == Context.MappingSimpleKey) && !indentation_;
|
||||||
increaseIndent(No.flow, indentless);
|
increaseIndent(No.flow, indentless);
|
||||||
state_ = &expectBlockSequenceItem!(Yes.first);
|
nextExpected(&expectBlockSequenceItem!(Yes.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle a block sequence item.
|
///Handle a block sequence item.
|
||||||
void expectBlockSequenceItem(Flag!"first" first)() @trusted
|
void expectBlockSequenceItem(Flag!"first" first)() @safe
|
||||||
{
|
{
|
||||||
static if(!first) if(event_.id == EventID.SequenceEnd)
|
static if(!first) if(event_.id == EventID.SequenceEnd)
|
||||||
{
|
{
|
||||||
indent_ = popIndent();
|
indent_ = popIndent();
|
||||||
state_ = popState();
|
nextExpected(popState());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeIndent();
|
writeIndent();
|
||||||
writeIndicator("-", Yes.needWhitespace, No.whitespace, Yes.indentation);
|
writeIndicator("-", Yes.needWhitespace, No.whitespace, Yes.indentation);
|
||||||
states_ ~= &expectBlockSequenceItem!(No.first);
|
pushState(&expectBlockSequenceItem!(No.first));
|
||||||
expectSequenceNode();
|
expectSequenceNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Block mapping handlers.
|
//Block mapping handlers.
|
||||||
|
|
||||||
///Handle a block mapping.
|
///Handle a block mapping.
|
||||||
void expectBlockMapping() @trusted
|
void expectBlockMapping() @safe
|
||||||
{
|
{
|
||||||
increaseIndent(No.flow);
|
increaseIndent(No.flow);
|
||||||
state_ = &expectBlockMappingKey!(Yes.first);
|
nextExpected(&expectBlockMappingKey!(Yes.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle a key in a block mapping.
|
///Handle a key in a block mapping.
|
||||||
void expectBlockMappingKey(Flag!"first" first)() @trusted
|
void expectBlockMappingKey(Flag!"first" first)() @safe
|
||||||
{
|
{
|
||||||
static if(!first) if(event_.id == EventID.MappingEnd)
|
static if(!first) if(event_.id == EventID.MappingEnd)
|
||||||
{
|
{
|
||||||
indent_ = popIndent();
|
indent_ = popIndent();
|
||||||
state_ = popState();
|
nextExpected(popState());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeIndent();
|
writeIndent();
|
||||||
if(checkSimpleKey())
|
if(checkSimpleKey())
|
||||||
{
|
{
|
||||||
states_ ~= &expectBlockMappingSimpleValue;
|
pushState(&expectBlockMappingSimpleValue);
|
||||||
expectMappingNode(true);
|
expectMappingNode(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeIndicator("?", Yes.needWhitespace, No.whitespace, Yes.indentation);
|
writeIndicator("?", Yes.needWhitespace, No.whitespace, Yes.indentation);
|
||||||
states_ ~= &expectBlockMappingValue;
|
pushState(&expectBlockMappingValue);
|
||||||
expectMappingNode();
|
expectMappingNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle a simple value in a block mapping.
|
///Handle a simple value in a block mapping.
|
||||||
void expectBlockMappingSimpleValue() @trusted
|
void expectBlockMappingSimpleValue() @safe
|
||||||
{
|
{
|
||||||
writeIndicator(":", No.needWhitespace);
|
writeIndicator(":", No.needWhitespace);
|
||||||
states_ ~= &expectBlockMappingKey!(No.first);
|
pushState(&expectBlockMappingKey!(No.first));
|
||||||
expectMappingNode();
|
expectMappingNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle a complex value in a block mapping.
|
///Handle a complex value in a block mapping.
|
||||||
void expectBlockMappingValue() @trusted
|
void expectBlockMappingValue() @safe
|
||||||
{
|
{
|
||||||
writeIndent();
|
writeIndent();
|
||||||
writeIndicator(":", Yes.needWhitespace, No.whitespace, Yes.indentation);
|
writeIndicator(":", Yes.needWhitespace, No.whitespace, Yes.indentation);
|
||||||
states_ ~= &expectBlockMappingKey!(No.first);
|
pushState(&expectBlockMappingKey!(No.first));
|
||||||
expectMappingNode();
|
expectMappingNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Checkers.
|
//Checkers.
|
||||||
|
|
||||||
///Check if an empty sequence is next.
|
///Check if an empty sequence is next.
|
||||||
bool checkEmptySequence() const @trusted pure nothrow
|
bool checkEmptySequence() const @safe pure nothrow
|
||||||
{
|
{
|
||||||
return event_.id == EventID.SequenceStart && events_.length > 0
|
return event_.id == EventID.SequenceStart && events_.length > 0
|
||||||
&& events_.peek().id == EventID.SequenceEnd;
|
&& events_.peek().id == EventID.SequenceEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
///Check if an empty mapping is next.
|
///Check if an empty mapping is next.
|
||||||
bool checkEmptyMapping() const @trusted pure nothrow
|
bool checkEmptyMapping() const @safe pure nothrow
|
||||||
{
|
{
|
||||||
return event_.id == EventID.MappingStart && events_.length > 0
|
return event_.id == EventID.MappingStart && events_.length > 0
|
||||||
&& events_.peek().id == EventID.MappingEnd;
|
&& events_.peek().id == EventID.MappingEnd;
|
||||||
|
@ -734,7 +737,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Process and write a scalar.
|
///Process and write a scalar.
|
||||||
void processScalar() @trusted
|
void processScalar() @safe
|
||||||
{
|
{
|
||||||
if(analysis_.flags.isNull){analysis_ = analyzeScalar(event_.value);}
|
if(analysis_.flags.isNull){analysis_ = analyzeScalar(event_.value);}
|
||||||
if(style_ == ScalarStyle.Invalid)
|
if(style_ == ScalarStyle.Invalid)
|
||||||
|
@ -1253,6 +1256,22 @@ struct Emitter
|
||||||
writeString(prefix);
|
writeString(prefix);
|
||||||
writeLineBreak();
|
writeLineBreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nextExpected(void delegate() @safe func) @trusted
|
||||||
|
{
|
||||||
|
state_ = func.funcptr;
|
||||||
|
}
|
||||||
|
void nextExpected(void function() @safe func) @safe
|
||||||
|
{
|
||||||
|
state_ = func;
|
||||||
|
}
|
||||||
|
void callNext() @trusted
|
||||||
|
{
|
||||||
|
void delegate() @safe func;
|
||||||
|
func.funcptr = state_;
|
||||||
|
func.ptr = &this;
|
||||||
|
func();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue