wrap unsafe portion of Emitter into @trusted helper functions

This commit is contained in:
Cameron Ross 2018-04-24 13:50:20 -03:00
parent aa1af974e8
commit 4cb78ff6f5
No known key found for this signature in database
GPG key ID: 777897D98DC91C54

View file

@ -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();
}
} }