@@ -1176,12 +1176,193 @@ func extractResultFields(types []reflect.Type) ([]reflect.StructField, func(int,
11761176 }
11771177}
11781178
1179+ type fromAnnotation struct {
1180+ targets []interface {}
1181+ types []reflect.Type
1182+ }
1183+
1184+ var _ Annotation = (* fromAnnotation )(nil )
1185+
1186+ // From is an [Annotation] that annotates the parameter(s) for a function (i.e. a
1187+ // constructor) to be accepted from other provided types. It is analogous to the
1188+ // [As] for parameter types to the constructor.
1189+ //
1190+ // For example,
1191+ //
1192+ // type Runner interface { Run() }
1193+ // func NewFooRunner() *FooRunner // implements Runner
1194+ // func NewRunnerWrap(r Runner) *RunnerWrap
1195+ //
1196+ // fx.Provide(
1197+ // fx.Annotate(
1198+ // NewRunnerWrap,
1199+ // fx.From(new(*FooRunner)),
1200+ // ),
1201+ // )
1202+ //
1203+ // Is equivalent to,
1204+ //
1205+ // fx.Provide(func(r *FooRunner) *RunnerWrap {
1206+ // // need *FooRunner instead of Runner
1207+ // return NewRunnerWrap(r)
1208+ // })
1209+ //
1210+ // When the annotated function takes in multiple parameters, each type gets
1211+ // mapped to corresponding positional parameter of the annotated function
1212+ //
1213+ // For example,
1214+ //
1215+ // func NewBarRunner() *BarRunner // implements Runner
1216+ // func NewRunnerWraps(r1 Runner, r2 Runner) *RunnerWraps
1217+ //
1218+ // fx.Provide(
1219+ // fx.Annotate(
1220+ // NewRunnerWraps,
1221+ // fx.From(new(*FooRunner), new(*BarRunner)),
1222+ // ),
1223+ // )
1224+ //
1225+ // Is equivalent to,
1226+ //
1227+ // fx.Provide(func(r1 *FooRunner, r2 *BarRunner) *RunnerWraps {
1228+ // return NewRunnerWraps(r1, r2)
1229+ // })
1230+ func From (interfaces ... interface {}) Annotation {
1231+ return & fromAnnotation {targets : interfaces }
1232+ }
1233+
1234+ func (fr * fromAnnotation ) apply (ann * annotated ) error {
1235+ if len (ann .From ) > 0 {
1236+ return errors .New ("cannot apply more than one line of From" )
1237+ }
1238+ ft := reflect .TypeOf (ann .Target )
1239+ fr .types = make ([]reflect.Type , len (fr .targets ))
1240+ for i , typ := range fr .targets {
1241+ if ft .IsVariadic () && i == ft .NumIn ()- 1 {
1242+ return errors .New ("fx.From: cannot annotate a variadic argument" )
1243+ }
1244+ t := reflect .TypeOf (typ )
1245+ if t == nil || t .Kind () != reflect .Ptr {
1246+ return fmt .Errorf ("fx.From: argument must be a pointer to a type that implements some interface: got %v" , t )
1247+ }
1248+ fr .types [i ] = t .Elem ()
1249+ }
1250+ ann .From = fr .types
1251+ return nil
1252+ }
1253+
1254+ // build builds and returns a constructor after applying a From annotation
1255+ func (fr * fromAnnotation ) build (ann * annotated ) (interface {}, error ) {
1256+ paramTypes , remap , err := fr .parameters (ann )
1257+ if err != nil {
1258+ return nil , err
1259+ }
1260+ resultTypes , _ := ann .currentResultTypes ()
1261+
1262+ origFn := reflect .ValueOf (ann .Target )
1263+ newFnType := reflect .FuncOf (paramTypes , resultTypes , false )
1264+ newFn := reflect .MakeFunc (newFnType , func (args []reflect.Value ) []reflect.Value {
1265+ args = remap (args )
1266+ return origFn .Call (args )
1267+ })
1268+ return newFn .Interface (), nil
1269+ }
1270+
1271+ // parameters returns the type for the parameters of the annotated function,
1272+ // and a function that maps the arguments of the annotated function
1273+ // back to the arguments of the target function.
1274+ func (fr * fromAnnotation ) parameters (ann * annotated ) (
1275+ types []reflect.Type ,
1276+ remap func ([]reflect.Value ) []reflect.Value ,
1277+ err error ,
1278+ ) {
1279+ ft := reflect .TypeOf (ann .Target )
1280+ types = make ([]reflect.Type , ft .NumIn ())
1281+ for i := 0 ; i < ft .NumIn (); i ++ {
1282+ types [i ] = ft .In (i )
1283+ }
1284+
1285+ // No parameter annotations. Return the original types
1286+ // and an identity function.
1287+ if len (fr .targets ) == 0 {
1288+ return types , func (args []reflect.Value ) []reflect.Value {
1289+ return args
1290+ }, nil
1291+ }
1292+
1293+ // Turn parameters into an fx.In struct.
1294+ inFields := []reflect.StructField {_inAnnotationField }
1295+
1296+ // The following situations may occur:
1297+ // 1. there was a variadic argument, so it was pre-transformed.
1298+ // 2. another parameter annotation was transformed (ex: ParamTags).
1299+ // so need to visit fields of the fx.In struct.
1300+ if len (types ) > 0 && isIn (types [0 ]) {
1301+ paramType := types [0 ]
1302+
1303+ for i := 1 ; i < paramType .NumField (); i ++ {
1304+ origField := paramType .Field (i )
1305+ field := reflect.StructField {
1306+ Name : origField .Name ,
1307+ Type : origField .Type ,
1308+ Tag : origField .Tag ,
1309+ }
1310+ if i - 1 < len (fr .types ) {
1311+ t := fr .types [i - 1 ]
1312+ if ! t .Implements (field .Type ) {
1313+ return nil , nil , fmt .Errorf ("invalid fx.From: %v does not implement %v" , t , field .Type )
1314+ }
1315+ field .Type = t
1316+ }
1317+
1318+ inFields = append (inFields , field )
1319+ }
1320+
1321+ types = []reflect.Type {reflect .StructOf (inFields )}
1322+ return types , func (args []reflect.Value ) []reflect.Value {
1323+ param := args [0 ]
1324+ args [0 ] = reflect .New (paramType ).Elem ()
1325+ for i := 1 ; i < paramType .NumField (); i ++ {
1326+ args [0 ].Field (i ).Set (param .Field (i ))
1327+ }
1328+ return args
1329+ }, nil
1330+ }
1331+
1332+ for i , t := range types {
1333+ field := reflect.StructField {
1334+ Name : fmt .Sprintf ("Field%d" , i ),
1335+ Type : t ,
1336+ }
1337+ if i < len (fr .types ) {
1338+ t := fr .types [i ]
1339+ if ! t .Implements (field .Type ) {
1340+ return nil , nil , fmt .Errorf ("invalid fx.From: %v does not implement %v" , t , field .Type )
1341+ }
1342+ field .Type = t
1343+ }
1344+
1345+ inFields = append (inFields , field )
1346+ }
1347+
1348+ types = []reflect.Type {reflect .StructOf (inFields )}
1349+ return types , func (args []reflect.Value ) []reflect.Value {
1350+ params := args [0 ]
1351+ args = args [:0 ]
1352+ for i := 0 ; i < ft .NumIn (); i ++ {
1353+ args = append (args , params .Field (i + 1 ))
1354+ }
1355+ return args
1356+ }, nil
1357+ }
1358+
11791359type annotated struct {
11801360 Target interface {}
11811361 Annotations []Annotation
11821362 ParamTags []string
11831363 ResultTags []string
11841364 As [][]reflect.Type
1365+ From []reflect.Type
11851366 FuncPtr uintptr
11861367 Hooks []* lifecycleHookAnnotation
11871368 // container is used to build private scopes for lifecycle hook functions
@@ -1202,6 +1383,9 @@ func (ann annotated) String() string {
12021383 if as := ann .As ; len (as ) > 0 {
12031384 fmt .Fprintf (& sb , ", fx.As(%v)" , as )
12041385 }
1386+ if from := ann .From ; len (from ) > 0 {
1387+ fmt .Fprintf (& sb , ", fx.From(%v)" , from )
1388+ }
12051389 return sb .String ()
12061390}
12071391
0 commit comments