Skip to content

Commit f09ca2b

Browse files
authored
Add Condense() and SaveTo() (#35)
`SaveTo()` added. Intermediate values can now be requested and written through pointers. `Collection.Condense()` added -- a collection can now be turned into a single injector. This can be done recursively. Combined with `SaveTo`, multiple copies of the same type can be generated and preserved separately. The `Reflective` type has been joined by new siblings: `ReflectiveInvoker`, `ReflectiveArgs`, and `ReflectiveWrapper`
1 parent bf7d347 commit f09ca2b

22 files changed

+1385
-336
lines changed

api.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,28 @@ type Collection struct {
1616
contents []*provider
1717
}
1818

19+
var _ Provider = &Collection{}
20+
1921
// Provider is an individual injector (function, constant, or
2022
// wrapper). Functions that take injectors, take interface{}.
2123
// Functions that return invjectors return Provider so that
2224
// methods can be attached.
2325
type Provider interface {
2426
thing
27+
String() string
28+
29+
// For single providers, DownFlows includes all inputs and
30+
// all outputs. For collections, Downflows only includes
31+
// the net inputs and net outputs.
32+
DownFlows() (inputs []reflect.Type, outputs []reflect.Type)
33+
34+
// For single providers, Upflows includes all consumes and
35+
// all returns. For collections, Upflows only includes
36+
// the net consumes and returns.
37+
//
38+
// Providers that return TerminalError are a special case and count as
39+
// producting error.
40+
UpFlows() (consume []reflect.Type, produce []reflect.Type)
2541
}
2642

2743
// Sequence creates a Collection of providers. Each collection must

bind.go

Lines changed: 54 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,11 @@ func doBind(sc *Collection, originalInvokeF *provider, originalInitF *provider,
3838

3939
// Add debugging provider
4040
{
41-
d := newProvider(func() *Debugging { return nil }, -1, "Debugging")
42-
d.cacheable = true
43-
d.mustCache = true
44-
d, err = characterizeFunc(d, charContext{inputsAreStatic: true})
41+
//nolint:govet // err is shadowing, who cares?
42+
d, err := makeDebuggingProvider()
4543
if err != nil {
46-
return fmt.Errorf("internal error #29: problem with debugging injectors: %w", err)
44+
return err
4745
}
48-
d.isSynthetic = true
4946
debuggingProvider = &d
5047
funcs = append(funcs, d)
5148
}
@@ -314,24 +311,29 @@ func doBind(sc *Collection, originalInvokeF *provider, originalInitF *provider,
314311

315312
debugln("SET INIT FUNC")
316313
if real {
317-
reflect.ValueOf(initF.fn).Elem().Set(
318-
reflect.MakeFunc(reflect.ValueOf(initF.fn).Type().Elem(),
319-
func(inputs []reflect.Value) []reflect.Value {
320-
debugln("INSIDE INIT")
321-
// if initDone panic, return error, or ignore?
322-
initOnce.Do(func() {
323-
outMap(baseValues, inputs)
324-
debugln("RUN STATIC CHAIN")
325-
_ = runStaticChain()
326-
})
327-
dumpValueArray(baseValues, "base values before init return", downVmap)
328-
out := inMap(baseValues)
329-
debugln("DONE INIT")
330-
dumpValueArray(out, "init return", nil)
331-
dumpF("init", initF)
332-
333-
return out
334-
}))
314+
initImp := func(inputs []reflect.Value) []reflect.Value {
315+
debugln("INSIDE INIT")
316+
// if initDone panic, return error, or ignore?
317+
initOnce.Do(func() {
318+
outMap(baseValues, inputs)
319+
debugln("RUN STATIC CHAIN")
320+
_ = runStaticChain()
321+
})
322+
dumpValueArray(baseValues, "base values before init return", downVmap)
323+
out := inMap(baseValues)
324+
debugln("DONE INIT")
325+
dumpValueArray(out, "init return", nil)
326+
dumpF("init", initF)
327+
328+
return out
329+
}
330+
if ri, ok := initF.fn.(ReflectiveInvoker); ok {
331+
ri.Set(initImp)
332+
} else {
333+
reflect.ValueOf(initF.fn).Elem().Set(
334+
reflect.MakeFunc(reflect.ValueOf(initF.fn).Type().Elem(),
335+
initImp))
336+
}
335337
}
336338
debugln("SET INIT FUNC - DONE")
337339

@@ -357,17 +359,22 @@ func doBind(sc *Collection, originalInvokeF *provider, originalInitF *provider,
357359

358360
debugln("SET INVOKE FUNC")
359361
if real {
360-
reflect.ValueOf(invokeF.fn).Elem().Set(
361-
reflect.MakeFunc(reflect.ValueOf(invokeF.fn).Type().Elem(),
362-
func(inputs []reflect.Value) []reflect.Value {
363-
initFunc()
364-
values := baseValues.Copy()
365-
dumpValueArray(values, "invoke - before input copy", downVmap)
366-
outMap(values, inputs)
367-
dumpValueArray(values, "invoke - after input copy", downVmap)
368-
f(values)
369-
return inMap(values)
370-
}))
362+
invokeImpl := func(inputs []reflect.Value) []reflect.Value {
363+
initFunc()
364+
values := baseValues.Copy()
365+
dumpValueArray(values, "invoke - before input copy", downVmap)
366+
outMap(values, inputs)
367+
dumpValueArray(values, "invoke - after input copy", downVmap)
368+
f(values)
369+
return inMap(values)
370+
}
371+
if ri, ok := invokeF.fn.(ReflectiveInvoker); ok {
372+
ri.Set(invokeImpl)
373+
} else {
374+
reflect.ValueOf(invokeF.fn).Elem().Set(
375+
reflect.MakeFunc(reflect.ValueOf(invokeF.fn).Type().Elem(),
376+
invokeImpl))
377+
}
371378
}
372379
debugln("SET INVOKE FUNC - DONE")
373380
}
@@ -396,3 +403,15 @@ func addToVmap(fm *provider, param flowType, vMap map[typeCode]int, rMap map[typ
396403
}
397404
}
398405
}
406+
407+
func makeDebuggingProvider() (*provider, error) {
408+
d := newProvider(func() *Debugging { return nil }, -1, "Debugging")
409+
d.cacheable = true
410+
d.mustCache = true
411+
d, err := characterizeFunc(d, charContext{inputsAreStatic: true})
412+
if err != nil {
413+
return nil, fmt.Errorf("internal error #29: problem with debugging injectors: %w", err)
414+
}
415+
d.isSynthetic = true
416+
return d, nil
417+
}

characterize.go

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ type charContext struct {
1313
inputsAreStatic bool
1414
}
1515

16-
type flowMapType [lastFlowType][]typeCode
16+
type flowMapType [lastFlowType]typeCodes
1717

1818
type characterization struct {
1919
name string
@@ -161,6 +161,9 @@ var (
161161
)
162162

163163
var noAnonymousFuncs = predicate("has an untyped functional argument", func(a testArgs) bool {
164+
if _, ok := a.fm.fn.(ReflectiveWrapper); ok {
165+
return false
166+
}
164167
return !hasAnonymousFuncs(typesIn(a.t), false) &&
165168
!hasAnonymousFuncs(typesOut(a.t), false)
166169
})
@@ -171,13 +174,30 @@ var noAnonymousExceptFirstInput = predicate("has extra untyped functional argume
171174
})
172175

173176
var hasInner = predicate("does not have an Inner function (untyped functional argument in the 1st position)", func(a testArgs) bool {
174-
t := a.t
175-
return t.Kind() == reflect.Func && t.NumIn() > 0 && t.In(0).Kind() == reflect.Func
177+
return isWrapper(a.t, a.fm.fn)
176178
})
177179

180+
func isWrapper(t reflectType, fn interface{}) bool {
181+
if _, ok := fn.(ReflectiveWrapper); ok {
182+
return true
183+
}
184+
return t.Kind() == reflect.Func && t.NumIn() > 0 && t.In(0).Kind() == reflect.Func
185+
}
186+
178187
var isFuncPointer = predicate("is not a pointer to a function", func(a testArgs) bool {
179-
t := a.t
180-
return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Func
188+
switch a.fm.fn.(type) {
189+
case ReflectiveInvoker:
190+
return true
191+
case Reflective, ReflectiveArgs:
192+
return false
193+
default:
194+
t := a.t
195+
return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Func
196+
}
197+
})
198+
199+
var isNotFuncPointer = predicate("is a pointer to a function", func(a testArgs) bool {
200+
return !isFuncPointer.test(a)
181201
})
182202

183203
var invokeRegistry = typeRegistry{
@@ -191,8 +211,13 @@ var invokeRegistry = typeRegistry{
191211
mutate: func(a testArgs) {
192212
a.fm.group = invokeGroup
193213
a.fm.class = initFunc
194-
a.fm.flows[outputParams] = toTypeCodes(typesIn(a.t.Elem()))
195-
a.fm.flows[bypassParams] = toTypeCodes(typesOut(a.t.Elem()))
214+
if _, ok := a.fm.fn.(ReflectiveInvoker); ok {
215+
a.fm.flows[outputParams] = toTypeCodes(typesIn(a.t))
216+
a.fm.flows[bypassParams] = toTypeCodes(typesOut(a.t))
217+
} else {
218+
a.fm.flows[outputParams] = toTypeCodes(typesIn(a.t.Elem()))
219+
a.fm.flows[bypassParams] = toTypeCodes(typesOut(a.t.Elem()))
220+
}
196221
a.fm.required = true
197222
a.fm.isSynthetic = true
198223
},
@@ -207,8 +232,13 @@ var invokeRegistry = typeRegistry{
207232
mutate: func(a testArgs) {
208233
a.fm.group = invokeGroup
209234
a.fm.class = invokeFunc
210-
a.fm.flows[outputParams] = toTypeCodes(typesIn(a.t.Elem()))
211-
a.fm.flows[receviedParams] = toTypeCodes(typesOut(a.t.Elem()))
235+
if _, ok := a.fm.fn.(ReflectiveInvoker); ok {
236+
a.fm.flows[outputParams] = toTypeCodes(typesIn(a.t))
237+
a.fm.flows[receviedParams] = toTypeCodes(typesOut(a.t))
238+
} else {
239+
a.fm.flows[outputParams] = toTypeCodes(typesIn(a.t.Elem()))
240+
a.fm.flows[receviedParams] = toTypeCodes(typesOut(a.t.Elem()))
241+
}
212242
a.fm.required = true
213243
a.fm.isSynthetic = true
214244
},
@@ -246,6 +276,7 @@ var handlerRegistry = typeRegistry{
246276
notMarkedNoCache,
247277
mustNotMemoize,
248278
notMarkedReorder,
279+
isNotFuncPointer,
249280
},
250281
mutate: func(a testArgs) {
251282
a.fm.group = staticGroup
@@ -268,6 +299,7 @@ var handlerRegistry = typeRegistry{
268299
notMarkedNoCache,
269300
mustNotMemoize,
270301
notMarkedReorder,
302+
isNotFuncPointer,
271303
},
272304
mutate: func(a testArgs) {
273305
a.fm.group = staticGroup
@@ -292,6 +324,7 @@ var handlerRegistry = typeRegistry{
292324
possibleMapKey,
293325
notMarkedSingleton,
294326
notMarkedReorder,
327+
isNotFuncPointer,
295328
},
296329
mutate: func(a testArgs) {
297330
a.fm.group = staticGroup
@@ -318,6 +351,7 @@ var handlerRegistry = typeRegistry{
318351
possibleMapKey,
319352
notMarkedSingleton,
320353
notMarkedReorder,
354+
isNotFuncPointer,
321355
},
322356
mutate: func(a testArgs) {
323357
a.fm.group = staticGroup
@@ -342,6 +376,7 @@ var handlerRegistry = typeRegistry{
342376
notMarkedNoCache,
343377
notMarkedSingleton,
344378
notMarkedReorder,
379+
isNotFuncPointer,
345380
},
346381
mutate: func(a testArgs) {
347382
a.fm.group = staticGroup
@@ -362,6 +397,7 @@ var handlerRegistry = typeRegistry{
362397
markedMemoized,
363398
unstaticOkay,
364399
notMarkedSingleton,
400+
isNotFuncPointer,
365401
},
366402
mutate: func(a testArgs) {
367403
a.fm.group = runGroup
@@ -383,6 +419,7 @@ var handlerRegistry = typeRegistry{
383419
mustNotMemoize,
384420
unstaticOkay,
385421
notMarkedSingleton,
422+
isNotFuncPointer,
386423
},
387424
mutate: func(a testArgs) {
388425
a.fm.group = runGroup
@@ -405,6 +442,7 @@ var handlerRegistry = typeRegistry{
405442
mustNotMemoize,
406443
notMarkedNoCache,
407444
notMarkedSingleton,
445+
isNotFuncPointer,
408446
},
409447
mutate: func(a testArgs) {
410448
a.fm.group = staticGroup
@@ -423,6 +461,7 @@ var handlerRegistry = typeRegistry{
423461
markedMemoized,
424462
unstaticOkay,
425463
notMarkedSingleton,
464+
isNotFuncPointer,
426465
},
427466
mutate: func(a testArgs) {
428467
a.fm.group = runGroup
@@ -442,6 +481,7 @@ var handlerRegistry = typeRegistry{
442481
mustNotMemoize,
443482
unstaticOkay,
444483
notMarkedSingleton,
484+
isNotFuncPointer,
445485
},
446486
mutate: func(a testArgs) {
447487
a.fm.group = runGroup
@@ -461,16 +501,23 @@ var handlerRegistry = typeRegistry{
461501
mustNotMemoize,
462502
unstaticOkay,
463503
notMarkedSingleton,
504+
isNotFuncPointer,
464505
},
465506
mutate: func(a testArgs) {
466507
in := typesIn(a.t)
467508
in[0] = reflect.TypeOf(noTypeExampleValue)
468509
a.fm.group = runGroup
469510
a.fm.class = wrapperFunc
470511
a.fm.flows[inputParams] = toTypeCodes(in)
471-
a.fm.flows[outputParams] = toTypeCodes(typesIn(a.t.In(0)))
472512
a.fm.flows[returnParams] = toTypeCodes(typesOut(a.t))
473-
a.fm.flows[receviedParams] = toTypeCodes(typesOut(a.t.In(0)))
513+
var inner reflectType
514+
if w, ok := a.fm.fn.(ReflectiveWrapper); ok {
515+
inner = wrappedReflective{w.Inner()}
516+
} else {
517+
inner = a.t.In(0)
518+
}
519+
a.fm.flows[outputParams] = toTypeCodes(typesIn(inner))
520+
a.fm.flows[receviedParams] = toTypeCodes(typesOut(inner))
474521
},
475522
},
476523

@@ -483,6 +530,7 @@ var handlerRegistry = typeRegistry{
483530
mustNotMemoize,
484531
unstaticOkay,
485532
notMarkedSingleton,
533+
isNotFuncPointer,
486534
},
487535
mutate: func(a testArgs) {
488536
a.fm.group = finalGroup
@@ -498,10 +546,10 @@ var handlerRegistry = typeRegistry{
498546
func (reg typeRegistry) characterizeFuncDetails(fm *provider, cc charContext) (*provider, error) {
499547
var rejectReasons []string
500548
var a testArgs
501-
if r, ok := fm.fn.(Reflective); ok {
549+
if r, ok := fm.fn.(ReflectiveArgs); ok {
502550
a = testArgs{
503551
fm: fm.copy(),
504-
t: reflectiveWrapper{r},
552+
t: wrappedReflective{r},
505553
isNil: false,
506554
cc: cc,
507555
}
@@ -533,7 +581,7 @@ Match:
533581
}
534582
a.fm.upRmap = make(map[typeCode]typeCode)
535583
a.fm.downRmap = make(map[typeCode]typeCode)
536-
a.fm.flows = [lastFlowType][]typeCode{}
584+
a.fm.flows = [lastFlowType]typeCodes{}
537585
match.mutate(a)
538586
return a.fm, nil
539587
}

characterize_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ type doesJ struct {
5252
func (dj *doesJ) I() int { return dj.j * 3 }
5353

5454
func params() flowMapType {
55-
return [lastFlowType][]typeCode{}
55+
return [lastFlowType]typeCodes{}
5656
}
5757

5858
func (flows flowMapType) returns(f ...typeCode) flowMapType {

0 commit comments

Comments
 (0)