@@ -1217,12 +1217,18 @@ function RttiCall(ParentAddress: pointer; DelphiWrapper: TPyDelphiWrapper;
12171217 const VarParamIndices: TArray<Integer>;
12181218 AParentAddrIsClass: Boolean = false): PPyObject; overload; forward ;
12191219
1220- function GetRttiAttr (ParentAddr: Pointer; ParentType: TRttiStructuredType;
1221- const AttrName: string; PyDelphiWrapper: TPyDelphiWrapper;
1222- out ErrMsg: string): PPyObject; forward ;
1220+ function GetRttiProperty (ParentAddr: Pointer; Prop: TRttiProperty;
1221+ PyDelphiWrapper: TPyDelphiWrapper; out ErrMsg: string): PPyObject; forward ;
12231222
1224- function SetRttiAttr (const ParentAddr: Pointer; ParentType: TRttiStructuredType;
1225- const AttrName: string; Value : PPyObject; PyDelphiWrapper: TPyDelphiWrapper;
1223+ function GetRttiField (ParentAddr: Pointer; Field: TRttiField;
1224+ PyDelphiWrapper: TPyDelphiWrapper; out ErrMsg: string): PPyObject; forward ;
1225+
1226+ function SetRttiProperty (const ParentAddr: Pointer; Prop: TRttiProperty;
1227+ Value : PPyObject; PyDelphiWrapper: TPyDelphiWrapper;
1228+ out ErrMsg: string): Boolean; forward ;
1229+
1230+ function SetRttiField (const ParentAddr: Pointer; Field: TRttiField;
1231+ Value : PPyObject; PyDelphiWrapper: TPyDelphiWrapper;
12261232 out ErrMsg: string): Boolean; forward ;
12271233
12281234function ValidateClassProperty (PyValue: PPyObject; TypeInfo: PTypeInfo;
@@ -1504,9 +1510,12 @@ function TExposedGetSet.GetterWrapper(AObj: PPyObject; AContext : Pointer): PPyO
15041510begin
15051511 Result := nil ;
15061512 if ValidateClassProperty(AObj, FParentRtti.Handle, Obj, LOutMsg) then
1507- // TODO: Optimize out the property/field lookup, by passing FRttiMember
1508- // directly to a GetRttiAttr/SetRtti overload
1509- Result := GetRttiAttr(Obj, FParentRtti, FRttiMember.Name , FPyDelphiWrapper, LOutMsg);
1513+ begin
1514+ if FRttiMember is TRttiProperty then
1515+ Result := GetRttiProperty(Obj, TRttiProperty(FRttiMember), FPyDelphiWrapper, LOutMsg)
1516+ else if FRttiMember is TRttiField then
1517+ Result := GetRttiField(Obj, TRttiField(FRttiMember), FPyDelphiWrapper, LOutMsg);
1518+ end ;
15101519
15111520 if not Assigned(Result) then
15121521 with GetPythonEngine do
@@ -1520,10 +1529,15 @@ function TExposedGetSet.SetterWrapper(AObj, AValue: PPyObject; AContext: Pointer
15201529 ErrMsg: string;
15211530begin
15221531 Result := -1 ;
1523- if ValidateClassProperty(AObj, FParentRtti.Handle, Obj, ErrMsg) and
1524- SetRttiAttr(Obj, FParentRtti, FRttiMember.Name , AValue, FPyDelphiWrapper, ErrMsg)
1525- then
1526- Result := 0 ;
1532+ if ValidateClassProperty(AObj, FParentRtti.Handle, Obj, ErrMsg) then
1533+ begin
1534+ if ((FRttiMember is TRttiProperty) and SetRttiProperty(Obj,
1535+ TRttiProperty(FRttiMember), AValue, FPyDelphiWrapper, ErrMsg)) or
1536+ ((FRttiMember is TRttiField) and SetRttiField(Obj,
1537+ TRttiField(FRttiMember), AValue, FPyDelphiWrapper, ErrMsg))
1538+ then
1539+ Result := 0
1540+ end ;
15271541
15281542 if Result <> 0 then
15291543 with GetPythonEngine do
@@ -3134,6 +3148,46 @@ function RttiCall(ParentAddress: pointer; DelphiWrapper: TPyDelphiWrapper;
31343148 end ;
31353149end ;
31363150
3151+ function GetRttiProperty (ParentAddr: Pointer; Prop: TRttiProperty;
3152+ PyDelphiWrapper: TPyDelphiWrapper; out ErrMsg: string): PPyObject;
3153+ begin
3154+ Result := nil ;
3155+ if Ord(Prop.Visibility) < Ord(mvPublic) then
3156+ ErrMsg := rs_NoAccess
3157+ else if not Prop.IsReadable then
3158+ ErrMsg := rs_NotReadable
3159+ else if Prop.PropertyType = nil then
3160+ ErrMsg := rs_ErrNoTypeInfo
3161+ else if Prop.PropertyType.TypeKind = tkMethod then
3162+ begin
3163+ if (Prop is TRttiInstanceProperty) and (Prop.Visibility = mvPublished) then
3164+ Result := PyDelphiWrapper.fEventHandlerList.GetCallable(TObject(ParentAddr),
3165+ TRttiInstanceProperty(Prop).PropInfo);
3166+ end
3167+ else
3168+ Result := TValueToPyObject(Prop.GetValue(ParentAddr), PyDelphiWrapper, ErrMsg);
3169+ end ;
3170+
3171+ function GetRttiField (ParentAddr: Pointer; Field: TRttiField;
3172+ PyDelphiWrapper: TPyDelphiWrapper; out ErrMsg: string): PPyObject;
3173+ begin
3174+ Result := nil ;
3175+ if Ord(Field.Visibility) < Ord(mvPublic) then
3176+ ErrMsg := rs_NoAccess
3177+ else if Field.FieldType = nil then
3178+ ErrMsg := rs_ErrNoTypeInfo
3179+ else if Field.FieldType.TypeKind in [tkRecord{ $IFDEF MANAGED_RECORD} ,tkMRecord{ $ENDIF} ] then
3180+ // Potentially dangerous as the returned value, which is a pointer into the object,
3181+ // could be stored on the python side, then the object freed, and the stored pointer later
3182+ // used to access no longer allocated memory
3183+ // But I can't see any good alternative if Python should be able to write directly into
3184+ // fields of a record that's part of an object.
3185+ Result := PyDelphiWrapper.WrapRecord(PByte(ParentAddr) + Field.Offset, TRttiStructuredType(Field.FieldType))
3186+ else
3187+ Result := TValueToPyObject(Field.GetValue(ParentAddr), PyDelphiWrapper, ErrMsg);
3188+ end ;
3189+
3190+
31373191function GetRttiAttr (ParentAddr: Pointer; ParentType: TRttiStructuredType;
31383192 const AttrName: string; PyDelphiWrapper: TPyDelphiWrapper;
31393193 out ErrMsg: string): PPyObject;
@@ -3161,41 +3215,12 @@ function GetRttiAttr(ParentAddr: Pointer; ParentType: TRttiStructuredType;
31613215 begin
31623216 Prop := ParentType.GetProperty(AttrName);
31633217 if Prop <> nil then
3164- begin
3165- if Ord(Prop.Visibility) < Ord(mvPublic) then
3166- ErrMsg := rs_NoAccess
3167- else if not Prop.IsReadable then
3168- ErrMsg := rs_NotReadable
3169- else if Prop.PropertyType = nil then
3170- ErrMsg := rs_ErrNoTypeInfo
3171- else if Prop.PropertyType.TypeKind = tkMethod then
3172- begin
3173- if (ParentType is TRttiInstanceType) and (Prop is TRttiInstanceProperty) then
3174- Result := PyDelphiWrapper.fEventHandlerList.GetCallable(TObject(ParentAddr),
3175- TRttiInstanceProperty(Prop).PropInfo);
3176- end
3177- else
3178- Result := TValueToPyObject(Prop.GetValue(ParentAddr), PyDelphiWrapper, ErrMsg);
3179- end
3218+ Result := GetRttiProperty(ParentAddr, Prop, PyDelphiWrapper, ErrMsg)
31803219 else
31813220 begin
31823221 Field := ParentType.GetField(AttrName);
31833222 if Field <> nil then
3184- begin
3185- if Ord(Field.Visibility) < Ord(mvPublic) then
3186- ErrMsg := rs_NoAccess
3187- else if Field.FieldType = nil then
3188- ErrMsg := rs_ErrNoTypeInfo
3189- else if Field.FieldType.TypeKind in [tkRecord{ $IFDEF MANAGED_RECORD} ,tkMRecord{ $ENDIF} ] then
3190- // Potentially dangerous as the returned value, which is a pointer into the object,
3191- // could be stored on the python side, then the object freed, and the stored pointer later
3192- // used to access no longer allocated memory
3193- // But I can't see any good alternative if Python should be able to write directly into
3194- // fields of a record that's part of an object.
3195- Result := PyDelphiWrapper.WrapRecord(PByte(ParentAddr) + Field.Offset, TRttiStructuredType(Field.FieldType))
3196- else
3197- Result := TValueToPyObject(Field.GetValue(ParentAddr), PyDelphiWrapper, ErrMsg);
3198- end
3223+ Result := GetRttiField(ParentAddr, Field, PyDelphiWrapper, ErrMsg)
31993224 else
32003225 ErrMsg := rs_UnknownAttribute;
32013226 end ;
@@ -3208,6 +3233,52 @@ function GetRttiAttr(ParentAddr: Pointer; ParentType: TRttiStructuredType;
32083233 end ;
32093234end ;
32103235
3236+ function SetRttiProperty (const ParentAddr: Pointer; Prop: TRttiProperty;
3237+ Value : PPyObject; PyDelphiWrapper: TPyDelphiWrapper;
3238+ out ErrMsg: string): Boolean;
3239+ var
3240+ AttrValue: TValue;
3241+ begin
3242+ Result := False;
3243+ if Ord(Prop.Visibility) < Ord(mvPublic) then
3244+ ErrMsg := rs_NoAccess
3245+ else if not Prop.IsWritable then
3246+ ErrMsg := rs_NotWritable
3247+ else if Prop.PropertyType = nil then
3248+ ErrMsg := rs_ErrNoTypeInfo
3249+ else if Prop.PropertyType.TypeKind = tkMethod then
3250+ begin
3251+ if (Prop is TRttiInstanceProperty) and (Prop.Visibility = mvPublished) then
3252+ Result := PyDelphiWrapper.EventHandlers.Link(TObject(ParentAddr),
3253+ (Prop as TRttiInstanceProperty).PropInfo, Value , ErrMsg)
3254+ else
3255+ ErrMsg := rs_NotPublished;
3256+ end
3257+ else if PyObjectToTValue(Value , Prop.PropertyType, AttrValue, ErrMsg) then
3258+ begin
3259+ Prop.SetValue(ParentAddr, AttrValue);
3260+ Result := True;
3261+ end ;
3262+ end ;
3263+
3264+ function SetRttiField (const ParentAddr: Pointer; Field: TRttiField;
3265+ Value : PPyObject; PyDelphiWrapper: TPyDelphiWrapper;
3266+ out ErrMsg: string): Boolean;
3267+ var
3268+ AttrValue: TValue;
3269+ begin
3270+ Result := False;
3271+ if Ord(Field.Visibility) < Ord(mvPublic) then
3272+ ErrMsg := rs_NoAccess
3273+ else if Field.FieldType = nil then
3274+ ErrMsg := rs_ErrNoTypeInfo
3275+ else if PyObjectToTValue(Value , Field.FieldType, AttrValue, ErrMsg) then
3276+ begin
3277+ Field.SetValue(ParentAddr, AttrValue);
3278+ Result := True;
3279+ end ;
3280+ end ;
3281+
32113282function SetRttiAttr (const ParentAddr: Pointer; ParentType: TRttiStructuredType;
32123283 const AttrName: string; Value : PPyObject; PyDelphiWrapper: TPyDelphiWrapper;
32133284 out ErrMsg: string): Boolean;
@@ -3221,42 +3292,12 @@ function SetRttiAttr(const ParentAddr: Pointer; ParentType: TRttiStructuredType
32213292 try
32223293 Prop := ParentType.GetProperty(AttrName);
32233294 if Prop <> nil then
3224- begin
3225- if Ord(Prop.Visibility) < Ord(mvPublic) then
3226- ErrMsg := rs_NoAccess
3227- else if not Prop.IsWritable then
3228- ErrMsg := rs_NotWritable
3229- else if Prop.PropertyType = nil then
3230- ErrMsg := rs_ErrNoTypeInfo
3231- else if Prop.PropertyType.TypeKind = tkMethod then
3232- begin
3233- if Prop.Visibility = mvPublished then
3234- Result := PyDelphiWrapper.EventHandlers.Link(TObject(ParentAddr),
3235- (Prop as TRttiInstanceProperty).PropInfo, Value , ErrMsg)
3236- else
3237- ErrMsg := rs_NotPublished;
3238- end
3239- else if PyObjectToTValue(Value , Prop.PropertyType, AttrValue, ErrMsg) then
3240- begin
3241- Prop.SetValue(ParentAddr, AttrValue);
3242- Result := True;
3243- end ;
3244- end
3295+ Result := SetRttiProperty(ParentAddr, Prop, Value , PyDelphiWrapper, ErrMsg)
32453296 else
32463297 begin
32473298 Field := ParentType.GetField(AttrName);
32483299 if Field <> nil then
3249- begin
3250- if Ord(Field.Visibility) < Ord(mvPublic) then
3251- ErrMsg := rs_NoAccess
3252- else if Field.FieldType = nil then
3253- ErrMsg := rs_ErrNoTypeInfo
3254- else if PyObjectToTValue(Value , Field.FieldType, AttrValue, ErrMsg) then
3255- begin
3256- Field.SetValue(ParentAddr, AttrValue);
3257- Result := True;
3258- end ;
3259- end
3300+ Result := SetRttiField(ParentAddr, Field, Value , PyDelphiWrapper, ErrMsg)
32603301 else
32613302 ErrMsg := rs_UnknownAttribute;
32623303 end ;
0 commit comments