| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/developer/debug/zxdb/console/async_output_buffer.h" |
| |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include "src/developer/debug/zxdb/common/err.h" |
| |
| namespace zxdb { |
| |
| void AsyncOutputBuffer::SetCompletionCallback(CompletionCallback cb) { |
| FX_DCHECK(!is_complete()); |
| |
| // Don't clobber with a different callback, but let it be cleared. |
| FX_DCHECK(!cb || !completion_callback_); |
| completion_callback_ = std::move(cb); |
| } |
| |
| void AsyncOutputBuffer::Append(std::string str, TextForegroundColor fg, TextBackgroundColor bg) { |
| FX_DCHECK(!marked_complete_); |
| nodes_.emplace_back(Span(std::move(str), fg, bg)); |
| } |
| |
| void AsyncOutputBuffer::Append(fxl::RefPtr<AsyncOutputBuffer> buf) { |
| FX_DCHECK(!marked_complete_); |
| |
| if (!buf->is_complete()) { |
| pending_resolution_++; |
| |
| // We're keeping a reference to the appended buffer so we know it's safe to capture |this|. We |
| // don't want to use a RefPtr here or it will create a reference cycle. |
| buf->SetCompletionCallback([this]() { |
| FX_DCHECK(pending_resolution_ > 0); |
| pending_resolution_--; |
| CheckComplete(); |
| }); |
| } |
| |
| nodes_.emplace_back(std::move(buf)); |
| } |
| |
| void AsyncOutputBuffer::Append(Syntax syntax, std::string str) { |
| FX_DCHECK(!marked_complete_); |
| nodes_.emplace_back(Span(syntax, std::move(str))); |
| } |
| |
| void AsyncOutputBuffer::Append(OutputBuffer buf) { |
| FX_DCHECK(!marked_complete_); |
| for (Span& span : buf.spans()) |
| nodes_.emplace_back(std::move(span)); |
| } |
| |
| void AsyncOutputBuffer::Append(const Err& err) { |
| FX_DCHECK(!marked_complete_); |
| nodes_.emplace_back(Span(Syntax::kNormal, err.msg())); |
| } |
| |
| void AsyncOutputBuffer::Complete() { |
| FX_DCHECK(!marked_complete_); |
| marked_complete_ = true; |
| CheckComplete(); |
| } |
| |
| void AsyncOutputBuffer::Complete(std::string str, TextForegroundColor fg, TextBackgroundColor bg) { |
| Append(std::move(str), fg, bg); |
| Complete(); |
| } |
| |
| void AsyncOutputBuffer::Complete(fxl::RefPtr<AsyncOutputBuffer> buf) { |
| Append(std::move(buf)); |
| Complete(); |
| } |
| |
| void AsyncOutputBuffer::Complete(Syntax syntax, std::string str) { |
| Append(std::move(str)); |
| Complete(); |
| } |
| |
| void AsyncOutputBuffer::Complete(OutputBuffer buf) { |
| Append(std::move(buf)); |
| Complete(); |
| } |
| |
| void AsyncOutputBuffer::Complete(const Err& err) { |
| Append(err); |
| Complete(); |
| } |
| |
| OutputBuffer AsyncOutputBuffer::DestructiveFlatten() { |
| FX_DCHECK(is_complete()); |
| |
| OutputBuffer out; |
| DestructiveCollectNodes(&out); |
| return out; |
| } |
| |
| void AsyncOutputBuffer::CheckComplete() { |
| if (is_complete() && completion_callback_) { |
| // Clear the object's callback before issuing it. |
| CompletionCallback stack_cb = std::move(completion_callback_); |
| stack_cb(); |
| } |
| } |
| |
| void AsyncOutputBuffer::DestructiveCollectNodes(OutputBuffer* out) { |
| FX_DCHECK(is_complete()); |
| for (auto& node : nodes_) { |
| if (std::holds_alternative<Span>(node)) |
| out->Append(std::move(std::get<Span>(node))); |
| else |
| std::get<Ref>(node)->DestructiveCollectNodes(out); |
| } |
| } |
| |
| } // namespace zxdb |