@@ -60,27 +60,32 @@ final class ComponentFlattenerImpl implements ComponentFlattener {
6060 .mapper (TextComponent .class , TextComponent ::content )
6161 .build ();
6262
63+ private static final int MAX_DEPTH = 512 ;
64+
6365 private final InheritanceAwareMap <Component , Handler > flatteners ;
6466 private final Function <Component , String > unknownHandler ;
65- private final int maximumDepth ;
67+ private final int maximumComplexity ;
6668
67- ComponentFlattenerImpl (final InheritanceAwareMap <Component , Handler > flatteners , final @ Nullable Function <Component , String > unknownHandler , final int maximumDepth ) {
69+ ComponentFlattenerImpl (final InheritanceAwareMap <Component , Handler > flatteners , final @ Nullable Function <Component , String > unknownHandler , final int maximumComplexity ) {
6870 this .flatteners = flatteners ;
6971 this .unknownHandler = unknownHandler ;
70- this .maximumDepth = maximumDepth ;
72+ this .maximumComplexity = maximumComplexity ;
7173 }
7274
7375 @ Override
7476 public void flatten (final @ NotNull Component input , final @ NotNull FlattenerListener listener ) {
75- this .flatten0 (input , listener , 0 );
77+ this .flatten0 (input , listener , new State (), 0 );
7678 }
7779
78- private void flatten0 (final @ NotNull Component input , final @ NotNull FlattenerListener listener , final int depth ) {
80+ private void flatten0 (final @ NotNull Component input , final @ NotNull FlattenerListener listener , final @ NotNull State state , final int depth ) {
7981 requireNonNull (input , "input" );
8082 requireNonNull (listener , "listener" );
8183 if (input == Component .empty ()) return ;
82- if (depth > this .maximumDepth ) {
83- throw new IllegalStateException ("Exceeded maximum depth of " + this .maximumDepth + " while attempting to flatten components!" );
84+ if (this .maximumComplexity != Builder .UNLIMITED_COMPLEXITY && state .complexity > this .maximumComplexity ) {
85+ throw new IllegalStateException ("Exceeded maximum complexity of " + this .maximumComplexity + " while attempting to flatten components!" );
86+ }
87+ if (depth >= MAX_DEPTH ) {
88+ throw new IllegalStateException ("Exceeded maximum depth of " + MAX_DEPTH + " while attempting to flatten components!" );
8489 }
8590
8691 final @ Nullable Handler flattener = this .flattener (input );
@@ -89,12 +94,14 @@ private void flatten0(final @NotNull Component input, final @NotNull FlattenerLi
8994 listener .pushStyle (inputStyle );
9095 try {
9196 if (flattener != null ) {
92- flattener .handle (this , input , listener , depth + 1 );
97+ state .complexity ++;
98+ flattener .handle (this , input , listener , state , depth + 1 );
9399 }
94100
95101 if (!input .children ().isEmpty () && listener .shouldContinue ()) {
96102 for (final Component child : input .children ()) {
97- this .flatten0 (child , listener , depth + 1 );
103+ state .complexity ++;
104+ this .flatten0 (child , listener , state , depth + 1 );
98105 }
99106 }
100107 } finally {
@@ -106,57 +113,59 @@ private void flatten0(final @NotNull Component input, final @NotNull FlattenerLi
106113 final Handler flattener = this .flatteners .get (test .getClass ());
107114
108115 if (flattener == null && this .unknownHandler != null ) {
109- return (self , component , listener , depth ) -> listener .component (this .unknownHandler .apply (component ));
116+ return (self , component , listener , state , depth ) -> listener .component (this .unknownHandler .apply (component ));
110117 } else {
111118 return flattener ;
112119 }
113120 }
114121
115122 @ Override
116123 public ComponentFlattener .@ NotNull Builder toBuilder () {
117- return new BuilderImpl (this .flatteners , this .unknownHandler , this .maximumDepth );
124+ return new BuilderImpl (this .flatteners , this .unknownHandler , this .maximumComplexity );
125+ }
126+
127+ static final class State {
128+ int complexity = 0 ;
118129 }
119130
120131 // A function that allows nesting other flatten operations
121132 @ FunctionalInterface
122133 interface Handler {
123- void handle (final ComponentFlattenerImpl self , final Component input , final FlattenerListener listener , final int depth );
134+ void handle (final ComponentFlattenerImpl self , final Component input , final FlattenerListener listener , final State state , final int depth );
124135 }
125136
126137 static final class BuilderImpl implements Builder {
127- private static final int DEFAULT_MAX_DEPTH = 512 ;
128-
129138 private final InheritanceAwareMap .Builder <Component , Handler > flatteners ;
130139 private @ Nullable Function <Component , String > unknownHandler ;
131- private int maximumDepth ;
140+ private int maximumComplexity ;
132141
133142 BuilderImpl () {
134143 this .flatteners = InheritanceAwareMap .<Component , Handler >builder ().strict (true );
135- this .maximumDepth = DEFAULT_MAX_DEPTH ;
144+ this .maximumComplexity = UNLIMITED_COMPLEXITY ;
136145 }
137146
138- BuilderImpl (final InheritanceAwareMap <Component , Handler > flatteners , final @ Nullable Function <Component , String > unknownHandler , final int maximumDepth ) {
147+ BuilderImpl (final InheritanceAwareMap <Component , Handler > flatteners , final @ Nullable Function <Component , String > unknownHandler , final int maximumComplexity ) {
139148 this .flatteners = InheritanceAwareMap .builder (flatteners ).strict (true );
140149 this .unknownHandler = unknownHandler ;
141- this .maximumDepth = maximumDepth ;
150+ this .maximumComplexity = maximumComplexity ;
142151 }
143152
144153 @ Override
145154 public @ NotNull ComponentFlattener build () {
146- return new ComponentFlattenerImpl (this .flatteners .build (), this .unknownHandler , this .maximumDepth );
155+ return new ComponentFlattenerImpl (this .flatteners .build (), this .unknownHandler , this .maximumComplexity );
147156 }
148157
149158 @ Override
150159 @ SuppressWarnings ("unchecked" )
151160 public <T extends Component > ComponentFlattener .@ NotNull Builder mapper (final @ NotNull Class <T > type , final @ NotNull Function <T , String > converter ) {
152- this .flatteners .put (type , (self , component , listener , depth ) -> listener .component (converter .apply ((T ) component )));
161+ this .flatteners .put (type , (self , component , listener , state , depth ) -> listener .component (converter .apply ((T ) component )));
153162 return this ;
154163 }
155164
156165 @ Override
157166 @ SuppressWarnings ("unchecked" )
158167 public <T extends Component > ComponentFlattener .@ NotNull Builder complexMapper (final @ NotNull Class <T > type , final @ NotNull BiConsumer <T , Consumer <Component >> converter ) {
159- this .flatteners .put (type , (self , component , listener , depth ) -> converter .accept ((T ) component , c -> self .flatten0 (c , listener , depth )));
168+ this .flatteners .put (type , (self , component , listener , state , depth ) -> converter .accept ((T ) component , c -> self .flatten0 (c , listener , state , depth )));
160169 return this ;
161170 }
162171
@@ -167,9 +176,11 @@ static final class BuilderImpl implements Builder {
167176 }
168177
169178 @ Override
170- public @ NotNull Builder maximumDepth (final int maximumDepth ) {
171- if (maximumDepth <= 0 ) throw new IllegalArgumentException ("maxDepth must be greater than 0, was " + maximumDepth );
172- this .maximumDepth = maximumDepth ;
179+ public @ NotNull Builder maximumComplexity (final int maximumComplexity ) {
180+ if (maximumComplexity != UNLIMITED_COMPLEXITY && maximumComplexity <= 0 ) {
181+ throw new IllegalArgumentException ("maximumComplexity must be greater than 0, was " + maximumComplexity );
182+ }
183+ this .maximumComplexity = maximumComplexity ;
173184 return this ;
174185 }
175186 }
0 commit comments