Skip to content

Commit 5696a63

Browse files
authored
Remove dynamic dispatch for AbstractTokenTargets (#744)
1 parent 6f827c6 commit 5696a63

File tree

2 files changed

+100
-48
lines changed

2 files changed

+100
-48
lines changed

librubyfmt/src/parser_state.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::heredoc_string::{HeredocKind, HeredocString};
55
use crate::line_tokens::*;
66
use crate::render_queue_writer::{MAX_LINE_LENGTH, RenderQueueWriter};
77
use crate::render_targets::{
8-
AbstractTokenTarget, BaseQueue, BreakableCallChainEntry, BreakableEntry, MultilineHandling,
8+
BaseQueue, Breakable, BreakableCallChainEntry, BreakableEntry, MultilineHandling,
99
};
1010
use crate::types::{ColNumber, LineNumber, SourceOffset};
1111
use log::debug;
@@ -65,7 +65,7 @@ pub struct ParserState {
6565
comments_hash: FileComments,
6666
heredoc_strings: Vec<HeredocString>,
6767
comments_to_insert: Option<CommentBlock>,
68-
breakable_entry_stack: Vec<Box<dyn AbstractTokenTarget>>,
68+
breakable_entry_stack: Vec<Breakable>,
6969
formatting_context: Vec<FormattingContext>,
7070
absorbing_indents: i32,
7171
insert_user_newlines: bool,
@@ -240,7 +240,8 @@ impl ParserState {
240240
self.shift_comments();
241241
let mut be = BreakableEntry::new(delims, &self.formatting_context);
242242
be.push_line_number(self.current_orig_line_number);
243-
self.breakable_entry_stack.push(Box::new(be));
243+
self.breakable_entry_stack
244+
.push(Breakable::DelimiterExpr(be));
244245

245246
self.new_block(|ps| {
246247
ps.emit_collapsing_newline();
@@ -262,7 +263,7 @@ impl ParserState {
262263
.breakable_entry_stack
263264
.pop()
264265
.expect("cannot have empty here because we just pushed")
265-
.to_breakable_entry()
266+
.into_breakable_entry()
266267
.expect("This should be the BreakableEntry we just pushed");
267268
self.push_target(ConcreteLineTokenAndTargets::BreakableEntry(insert_be));
268269
}
@@ -276,7 +277,8 @@ impl ParserState {
276277
self.shift_comments();
277278
let mut be = BreakableEntry::new(delims, &self.formatting_context);
278279
be.push_line_number(self.current_orig_line_number);
279-
self.breakable_entry_stack.push(Box::new(be));
280+
self.breakable_entry_stack
281+
.push(Breakable::DelimiterExpr(be));
280282

281283
self.new_block(|ps| f(ps));
282284

@@ -290,7 +292,7 @@ impl ParserState {
290292
.breakable_entry_stack
291293
.pop()
292294
.expect("cannot have empty here because we just pushed")
293-
.to_breakable_entry()
295+
.into_breakable_entry()
294296
.expect("This should be the BreakableEntry we just pushed");
295297
self.push_target(ConcreteLineTokenAndTargets::BreakableEntry(insert_be));
296298
}
@@ -305,15 +307,15 @@ impl ParserState {
305307
self.shift_comments();
306308
let mut be = BreakableCallChainEntry::new(&self.formatting_context, mulitiline_handling);
307309
be.push_line_number(self.current_orig_line_number);
308-
self.breakable_entry_stack.push(Box::new(be));
310+
self.breakable_entry_stack.push(Breakable::CallChain(be));
309311

310312
f(self);
311313

312314
let insert_bcce = self
313315
.breakable_entry_stack
314316
.pop()
315317
.expect("cannot have empty here because we just pushed")
316-
.to_breakable_call_chain()
318+
.into_breakable_call_chain()
317319
.expect("This should be the BreakableCallChainEntry we just pushed");
318320
self.push_target(ConcreteLineTokenAndTargets::BreakableCallChainEntry(
319321
insert_bcce,
@@ -812,9 +814,9 @@ impl ParserState {
812814
if let Some(entry) = self.breakable_entry_stack.last_mut() {
813815
entry.insert_at(
814816
insert_idx,
815-
Box::new(std::iter::once(AbstractLineToken::ConcreteLineToken(
817+
std::iter::once(AbstractLineToken::ConcreteLineToken(
816818
ConcreteLineToken::HardNewLine,
817-
))),
819+
)),
818820
);
819821
} else {
820822
self.insert_concrete_tokens(
@@ -915,7 +917,7 @@ impl ParserState {
915917
match self.breakable_entry_stack.last_mut() {
916918
Some(be) => be.insert_at(
917919
insert_idx,
918-
Box::new(clts.into_iter().map(AbstractLineToken::ConcreteLineToken)),
920+
clts.into_iter().map(AbstractLineToken::ConcreteLineToken),
919921
),
920922
None => self.render_queue.insert_at(
921923
insert_idx,

librubyfmt/src/render_targets.rs

Lines changed: 87 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,9 @@ impl BaseQueue {
4949

5050
pub trait AbstractTokenTarget: std::fmt::Debug {
5151
fn push(&mut self, lt: AbstractLineToken);
52-
fn insert_at(&mut self, idx: usize, tokens: Box<dyn Iterator<Item = AbstractLineToken> + '_>);
5352
fn into_tokens(self, ct: ConvertType) -> Vec<ConcreteLineTokenAndTargets>;
5453
fn is_multiline(&self) -> bool;
55-
fn push_line_number(&mut self, number: LineNumber);
5654
fn single_line_string_length(&self, current_line_length: usize) -> usize;
57-
fn to_breakable_entry(self: Box<Self>) -> Option<BreakableEntry>;
58-
fn to_breakable_call_chain(self: Box<Self>) -> Option<BreakableCallChainEntry>;
5955
fn tokens(&self) -> &Vec<AbstractLineToken>;
6056
fn any_collapsing_newline_has_heredoc_content(&self) -> bool;
6157

@@ -96,22 +92,10 @@ pub struct BreakableEntry {
9692
}
9793

9894
impl AbstractTokenTarget for BreakableEntry {
99-
fn to_breakable_entry(self: Box<Self>) -> Option<BreakableEntry> {
100-
Some(*self)
101-
}
102-
103-
fn to_breakable_call_chain(self: Box<Self>) -> Option<BreakableCallChainEntry> {
104-
None
105-
}
106-
10795
fn push(&mut self, lt: AbstractLineToken) {
10896
self.tokens.push(lt);
10997
}
11098

111-
fn insert_at(&mut self, idx: usize, tokens: Box<dyn Iterator<Item = AbstractLineToken> + '_>) {
112-
insert_at(idx, &mut self.tokens, tokens)
113-
}
114-
11599
fn into_tokens(self, ct: ConvertType) -> Vec<ConcreteLineTokenAndTargets> {
116100
match ct {
117101
ConvertType::MultiLine => {
@@ -141,10 +125,6 @@ impl AbstractTokenTarget for BreakableEntry {
141125
self.single_line_len() + current_line_length
142126
}
143127

144-
fn push_line_number(&mut self, number: LineNumber) {
145-
self.multiline_tracker.on_line(number);
146-
}
147-
148128
fn is_multiline(&self) -> bool {
149129
self.multiline_tracker.is_multiline()
150130
|| self.any_collapsing_newline_has_heredoc_content()
@@ -181,6 +161,14 @@ impl BreakableEntry {
181161
}
182162
}
183163

164+
pub fn insert_at(&mut self, idx: usize, tokens: impl IntoIterator<Item = AbstractLineToken>) {
165+
insert_at(idx, &mut self.tokens, tokens)
166+
}
167+
168+
pub fn push_line_number(&mut self, number: LineNumber) {
169+
self.multiline_tracker.on_line(number);
170+
}
171+
184172
pub fn in_string_embexpr(&self) -> bool {
185173
self.in_string_embexpr
186174
}
@@ -234,26 +222,14 @@ pub struct BreakableCallChainEntry {
234222
}
235223

236224
impl AbstractTokenTarget for BreakableCallChainEntry {
237-
fn to_breakable_entry(self: Box<Self>) -> Option<BreakableEntry> {
238-
None
239-
}
240-
241225
fn tokens(&self) -> &Vec<AbstractLineToken> {
242226
&self.tokens
243227
}
244228

245-
fn to_breakable_call_chain(self: Box<Self>) -> Option<BreakableCallChainEntry> {
246-
Some(*self)
247-
}
248-
249229
fn push(&mut self, lt: AbstractLineToken) {
250230
self.tokens.push(lt);
251231
}
252232

253-
fn insert_at(&mut self, idx: usize, tokens: Box<dyn Iterator<Item = AbstractLineToken> + '_>) {
254-
insert_at(idx, &mut self.tokens, tokens)
255-
}
256-
257233
fn into_tokens(self, ct: ConvertType) -> Vec<ConcreteLineTokenAndTargets> {
258234
match ct {
259235
ConvertType::MultiLine => self
@@ -361,11 +337,6 @@ impl AbstractTokenTarget for BreakableCallChainEntry {
361337
+ current_line_length
362338
}
363339

364-
fn push_line_number(&mut self, _number: LineNumber) {
365-
// No-op, BreakableCallChainEntry has custom multilining logic
366-
// that doesn't depend on the source line numbers
367-
}
368-
369340
fn is_multiline(&self) -> bool {
370341
if self.begins_with_heredoc() {
371342
return true;
@@ -452,6 +423,18 @@ impl BreakableCallChainEntry {
452423
}
453424
}
454425

426+
pub fn insert_at<I>(&mut self, idx: usize, tokens: I)
427+
where
428+
I: IntoIterator<Item = AbstractLineToken>,
429+
{
430+
insert_at(idx, &mut self.tokens, tokens)
431+
}
432+
433+
pub fn push_line_number(&mut self, _number: LineNumber) {
434+
// No-op, BreakableCallChainEntry has custom multilining logic
435+
// that doesn't depend on the source line numbers
436+
}
437+
455438
/// Removes `BeginCallChainIndent` and `EndCallChainIndent`, which is only really
456439
/// necessary when rendering a call chain as single-line. This prevents unnecessariliy
457440
/// increasing the indentation for a trailing block in e.g. `thing.each do; /* block */; end`
@@ -484,6 +467,73 @@ impl BreakableCallChainEntry {
484467
}
485468
}
486469

470+
#[derive(Debug)]
471+
pub enum Breakable {
472+
DelimiterExpr(BreakableEntry),
473+
CallChain(BreakableCallChainEntry),
474+
}
475+
476+
impl Breakable {
477+
pub fn push(&mut self, lt: AbstractLineToken) {
478+
match self {
479+
Breakable::DelimiterExpr(be) => be.push(lt),
480+
Breakable::CallChain(bcce) => bcce.push(lt),
481+
}
482+
}
483+
484+
pub fn insert_at<I>(&mut self, idx: usize, tokens: I)
485+
where
486+
I: IntoIterator<Item = AbstractLineToken>,
487+
{
488+
match self {
489+
Breakable::DelimiterExpr(be) => be.insert_at(idx, tokens),
490+
Breakable::CallChain(bcce) => bcce.insert_at(idx, tokens),
491+
}
492+
}
493+
494+
pub fn push_line_number(&mut self, number: LineNumber) {
495+
match self {
496+
Breakable::DelimiterExpr(be) => be.push_line_number(number),
497+
Breakable::CallChain(bcce) => bcce.push_line_number(number),
498+
}
499+
}
500+
501+
pub fn len(&self) -> usize {
502+
match self {
503+
Breakable::DelimiterExpr(be) => be.len(),
504+
Breakable::CallChain(bcce) => bcce.len(),
505+
}
506+
}
507+
508+
pub fn last_token_is_a_newline(&self) -> bool {
509+
match self {
510+
Breakable::DelimiterExpr(be) => be.last_token_is_a_newline(),
511+
Breakable::CallChain(bcce) => bcce.last_token_is_a_newline(),
512+
}
513+
}
514+
515+
pub fn index_of_prev_newline(&self) -> Option<usize> {
516+
match self {
517+
Breakable::DelimiterExpr(be) => be.index_of_prev_newline(),
518+
Breakable::CallChain(bcce) => bcce.index_of_prev_newline(),
519+
}
520+
}
521+
522+
pub fn into_breakable_entry(self) -> Option<BreakableEntry> {
523+
match self {
524+
Breakable::DelimiterExpr(be) => Some(be),
525+
Breakable::CallChain(_) => None,
526+
}
527+
}
528+
529+
pub fn into_breakable_call_chain(self) -> Option<BreakableCallChainEntry> {
530+
match self {
531+
Breakable::DelimiterExpr(_) => None,
532+
Breakable::CallChain(bcce) => Some(bcce),
533+
}
534+
}
535+
}
536+
487537
/// Tracks whether tokens span multiple source lines.
488538
#[derive(Debug, Clone)]
489539
struct MultilineTracker {

0 commit comments

Comments
 (0)