PageRenderTime 48ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/_weakref.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 919 lines | 696 code | 179 blank | 44 comment | 111 complexity | 315f12dd5eb7ef60bee0176ee7d27414 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Runtime.CompilerServices;
  19. using IronPython.Runtime;
  20. using IronPython.Runtime.Exceptions;
  21. using IronPython.Runtime.Operations;
  22. using IronPython.Runtime.Types;
  23. using Microsoft.Scripting;
  24. using Microsoft.Scripting.Actions;
  25. using Microsoft.Scripting.Runtime;
  26. using Microsoft.Scripting.Utils;
  27. [assembly: PythonModule("_weakref", typeof(IronPython.Modules.PythonWeakRef))]
  28. namespace IronPython.Modules {
  29. public static partial class PythonWeakRef {
  30. public const string __doc__ = "Provides support for creating weak references and proxies to objects";
  31. internal static IWeakReferenceable ConvertToWeakReferenceable(object obj) {
  32. IWeakReferenceable iwr = obj as IWeakReferenceable;
  33. if (iwr != null) return iwr;
  34. throw PythonOps.TypeError("cannot create weak reference to '{0}' object", PythonOps.GetPythonTypeName(obj));
  35. }
  36. public static int getweakrefcount(object @object) {
  37. return @ref.GetWeakRefCount(@object);
  38. }
  39. public static List getweakrefs(object @object) {
  40. return @ref.GetWeakRefs(@object);
  41. }
  42. public static object proxy(CodeContext context, object @object) {
  43. return proxy(context, @object, null);
  44. }
  45. public static object proxy(CodeContext context, object @object, object callback) {
  46. if (PythonOps.IsCallable(context, @object)) {
  47. return weakcallableproxy.MakeNew(context, @object, callback);
  48. } else {
  49. return weakproxy.MakeNew(context, @object, callback);
  50. }
  51. }
  52. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
  53. public static readonly PythonType CallableProxyType = DynamicHelpers.GetPythonTypeFromType(typeof(weakcallableproxy));
  54. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
  55. public static readonly PythonType ProxyType = DynamicHelpers.GetPythonTypeFromType(typeof(weakproxy));
  56. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
  57. public static readonly PythonType ReferenceType = DynamicHelpers.GetPythonTypeFromType(typeof(@ref));
  58. [PythonType]
  59. public class @ref : IStructuralEquatable
  60. #if CLR2
  61. , IValueEquality
  62. #endif
  63. {
  64. private WeakHandle _target;
  65. private int _hashVal;
  66. private bool _fHasHash;
  67. #region Python Constructors
  68. public static object __new__(CodeContext context, PythonType cls, object @object) {
  69. IWeakReferenceable iwr = ConvertToWeakReferenceable(@object);
  70. if (cls == DynamicHelpers.GetPythonTypeFromType(typeof(@ref))) {
  71. WeakRefTracker wrt = iwr.GetWeakRef();
  72. if (wrt != null) {
  73. for (int i = 0; i < wrt.HandlerCount; i++) {
  74. if (wrt.GetHandlerCallback(i) == null && wrt.GetWeakRef(i) is @ref) {
  75. return wrt.GetWeakRef(i);
  76. }
  77. }
  78. }
  79. return new @ref(@object);
  80. } else {
  81. return cls.CreateInstance(context, @object);
  82. }
  83. }
  84. public static object __new__(CodeContext context, PythonType cls, object @object, object callback) {
  85. if (callback == null) return __new__(context, cls, @object);
  86. if (cls == DynamicHelpers.GetPythonTypeFromType(typeof(@ref))) {
  87. return new @ref(@object, callback);
  88. } else {
  89. return cls.CreateInstance(context, @object, callback);
  90. }
  91. }
  92. #endregion
  93. #region Constructors
  94. public @ref(object @object)
  95. : this(@object, null) {
  96. }
  97. public @ref(object @object, object callback) {
  98. WeakRefHelpers.InitializeWeakRef(this, @object, callback);
  99. this._target = new WeakHandle(@object, false);
  100. }
  101. #endregion
  102. #region Finalizer
  103. ~@ref() {
  104. // remove our self from the chain...
  105. try {
  106. if (_target.IsAlive) {
  107. IWeakReferenceable iwr = _target.Target as IWeakReferenceable;
  108. if (iwr != null) {
  109. WeakRefTracker wrt = iwr.GetWeakRef();
  110. if (wrt != null) {
  111. // weak reference being finalized before target object,
  112. // we don't want to run the callback when the object is
  113. // finalized.
  114. wrt.RemoveHandler(this);
  115. }
  116. }
  117. _target.Free();
  118. }
  119. } catch (InvalidOperationException) {
  120. // target was freed
  121. }
  122. }
  123. #endregion
  124. #region Static helpers
  125. internal static int GetWeakRefCount(object o) {
  126. IWeakReferenceable iwr = o as IWeakReferenceable;
  127. if (iwr != null) {
  128. WeakRefTracker wrt = iwr.GetWeakRef();
  129. if (wrt != null) return wrt.HandlerCount;
  130. }
  131. return 0;
  132. }
  133. internal static List GetWeakRefs(object o) {
  134. List l = new List();
  135. IWeakReferenceable iwr = o as IWeakReferenceable;
  136. if (iwr != null) {
  137. WeakRefTracker wrt = iwr.GetWeakRef();
  138. if (wrt != null) {
  139. for (int i = 0; i < wrt.HandlerCount; i++) {
  140. l.AddNoLock(wrt.GetWeakRef(i));
  141. }
  142. }
  143. }
  144. return l;
  145. }
  146. #endregion
  147. [SpecialName]
  148. public object Call(CodeContext context) {
  149. if (!_target.IsAlive) {
  150. throw PythonOps.ReferenceError("weak object has gone away");
  151. }
  152. try {
  153. object res = _target.Target;
  154. GC.KeepAlive(this);
  155. return res;
  156. } catch (InvalidOperationException) {
  157. throw PythonOps.ReferenceError("weak object has gone away");
  158. }
  159. }
  160. [return: MaybeNotImplemented]
  161. public static NotImplementedType operator >(@ref self, object other) {
  162. return PythonOps.NotImplemented;
  163. }
  164. [return: MaybeNotImplemented]
  165. public static NotImplementedType operator <(@ref self, object other) {
  166. return PythonOps.NotImplemented;
  167. }
  168. [return: MaybeNotImplemented]
  169. public static NotImplementedType operator <=(@ref self, object other) {
  170. return PythonOps.NotImplemented;
  171. }
  172. [return: MaybeNotImplemented]
  173. public static NotImplementedType operator >=(@ref self, object other) {
  174. return PythonOps.NotImplemented;
  175. }
  176. #region IValueEquality Members
  177. #if CLR2
  178. int IValueEquality.GetValueHashCode() {
  179. return __hash__(DefaultContext.Default);
  180. }
  181. bool IValueEquality.ValueEquals(object other) {
  182. return EqualsWorker(other, null);
  183. }
  184. #endif
  185. #endregion
  186. #region IStructuralEquatable Members
  187. /// <summary>
  188. /// Special hash function because IStructuralEquatable.GetHashCode is not allowed to throw.
  189. /// </summary>
  190. public int __hash__(CodeContext/*!*/ context) {
  191. if (!_fHasHash) {
  192. object refObj = _target.Target;
  193. if (refObj == null) throw PythonOps.TypeError("weak object has gone away");
  194. GC.KeepAlive(this);
  195. _hashVal = PythonContext.GetContext(context).EqualityComparerNonGeneric.GetHashCode(refObj);
  196. _fHasHash = true;
  197. }
  198. return _hashVal;
  199. }
  200. int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
  201. if (!_fHasHash) {
  202. object refObj = _target.Target;
  203. GC.KeepAlive(this);
  204. _hashVal = comparer.GetHashCode(refObj);
  205. _fHasHash = true;
  206. }
  207. return _hashVal;
  208. }
  209. bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) {
  210. return EqualsWorker(other, comparer);
  211. }
  212. private bool EqualsWorker(object other, IEqualityComparer comparer) {
  213. if (object.ReferenceEquals(this, other)) {
  214. return true;
  215. }
  216. bool fResult = false;
  217. @ref wr = other as @ref;
  218. if (wr != null) {
  219. object ourTarget = _target.Target;
  220. object itsTarget = wr._target.Target;
  221. GC.KeepAlive(this);
  222. GC.KeepAlive(wr);
  223. if (ourTarget != null && itsTarget != null) {
  224. fResult = RefEquals(ourTarget, itsTarget, comparer);
  225. }
  226. }
  227. GC.KeepAlive(this);
  228. return fResult;
  229. }
  230. /// <summary>
  231. /// Special equals because none of the special cases in Ops.Equals
  232. /// are applicable here, and the reference equality check breaks some tests.
  233. /// </summary>
  234. private static bool RefEquals(object x, object y, IEqualityComparer comparer) {
  235. CodeContext context;
  236. if (comparer != null && comparer is PythonContext.PythonEqualityComparer) {
  237. context = ((PythonContext.PythonEqualityComparer)comparer).Context.SharedContext;
  238. } else {
  239. context = DefaultContext.Default;
  240. }
  241. object ret;
  242. if (PythonTypeOps.TryInvokeBinaryOperator(context, x, y, "__eq__", out ret) &&
  243. ret != NotImplementedType.Value) {
  244. return (bool)ret;
  245. }
  246. if (PythonTypeOps.TryInvokeBinaryOperator(context, y, x, "__eq__", out ret) &&
  247. ret != NotImplementedType.Value) {
  248. return (bool)ret;
  249. }
  250. if (comparer != null) {
  251. return comparer.Equals(x, y);
  252. }
  253. return x.Equals(y);
  254. }
  255. #endregion
  256. }
  257. [PythonType, DynamicBaseTypeAttribute, PythonHidden]
  258. public sealed partial class weakproxy : IPythonObject, ICodeFormattable, IProxyObject, IPythonMembersList, IStructuralEquatable
  259. #if CLR2
  260. , IValueEquality
  261. #endif
  262. {
  263. private readonly WeakHandle _target;
  264. private readonly CodeContext/*!*/ _context;
  265. #region Python Constructors
  266. internal static object MakeNew(CodeContext/*!*/ context, object @object, object callback) {
  267. IWeakReferenceable iwr = ConvertToWeakReferenceable(@object);
  268. if (callback == null) {
  269. WeakRefTracker wrt = iwr.GetWeakRef();
  270. if (wrt != null) {
  271. for (int i = 0; i < wrt.HandlerCount; i++) {
  272. if (wrt.GetHandlerCallback(i) == null && wrt.GetWeakRef(i) is weakproxy) {
  273. return wrt.GetWeakRef(i);
  274. }
  275. }
  276. }
  277. }
  278. return new weakproxy(context, @object, callback);
  279. }
  280. #endregion
  281. #region Constructors
  282. private weakproxy(CodeContext/*!*/ context, object target, object callback) {
  283. WeakRefHelpers.InitializeWeakRef(this, target, callback);
  284. _target = new WeakHandle(target, false);
  285. _context = context;
  286. }
  287. #endregion
  288. #region Finalizer
  289. ~weakproxy() {
  290. // remove our self from the chain...
  291. try {
  292. IWeakReferenceable iwr = _target.Target as IWeakReferenceable;
  293. if (iwr != null) {
  294. WeakRefTracker wrt = iwr.GetWeakRef();
  295. wrt.RemoveHandler(this);
  296. }
  297. _target.Free();
  298. } catch (InvalidOperationException) {
  299. // target was freed
  300. }
  301. }
  302. #endregion
  303. #region private members
  304. /// <summary>
  305. /// gets the object or throws a reference exception
  306. /// </summary>
  307. object GetObject() {
  308. object res;
  309. if (!TryGetObject(out res)) {
  310. throw PythonOps.ReferenceError("weakly referenced object no longer exists");
  311. }
  312. return res;
  313. }
  314. bool TryGetObject(out object result) {
  315. try {
  316. result = _target.Target;
  317. if (result == null) return false;
  318. GC.KeepAlive(this);
  319. return true;
  320. } catch (InvalidOperationException) {
  321. result = null;
  322. return false;
  323. }
  324. }
  325. #endregion
  326. #region IPythonObject Members
  327. PythonDictionary IPythonObject.Dict {
  328. get {
  329. IPythonObject sdo = GetObject() as IPythonObject;
  330. if (sdo != null) {
  331. return sdo.Dict;
  332. }
  333. return null;
  334. }
  335. }
  336. PythonDictionary IPythonObject.SetDict(PythonDictionary dict) {
  337. return (GetObject() as IPythonObject).SetDict(dict);
  338. }
  339. bool IPythonObject.ReplaceDict(PythonDictionary dict) {
  340. return (GetObject() as IPythonObject).ReplaceDict(dict);
  341. }
  342. void IPythonObject.SetPythonType(PythonType newType) {
  343. (GetObject() as IPythonObject).SetPythonType(newType);
  344. }
  345. PythonType IPythonObject.PythonType {
  346. get {
  347. return DynamicHelpers.GetPythonTypeFromType(typeof(weakproxy));
  348. }
  349. }
  350. object[] IPythonObject.GetSlots() { return null; }
  351. object[] IPythonObject.GetSlotsCreate() { return null; }
  352. #endregion
  353. #region object overloads
  354. public override string ToString() {
  355. return PythonOps.ToString(GetObject());
  356. }
  357. #endregion
  358. #region ICodeFormattable Members
  359. public string/*!*/ __repr__(CodeContext/*!*/ context) {
  360. object obj = _target.Target;
  361. GC.KeepAlive(this);
  362. return String.Format("<weakproxy at {0} to {1} at {2}>",
  363. IdDispenser.GetId(this),
  364. PythonOps.GetPythonTypeName(obj),
  365. IdDispenser.GetId(obj));
  366. }
  367. #endregion
  368. #region Custom member access
  369. [SpecialName]
  370. public object GetCustomMember(CodeContext/*!*/ context, string name) {
  371. object value, o = GetObject();
  372. if (PythonOps.TryGetBoundAttr(context, o, name, out value)) {
  373. return value;
  374. }
  375. return OperationFailed.Value;
  376. }
  377. [SpecialName]
  378. public void SetMember(CodeContext/*!*/ context, string name, object value) {
  379. object o = GetObject();
  380. PythonOps.SetAttr(context, o, name, value);
  381. }
  382. [SpecialName]
  383. public void DeleteMember(CodeContext/*!*/ context, string name) {
  384. object o = GetObject();
  385. PythonOps.DeleteAttr(context, o, name);
  386. }
  387. IList<string> IMembersList.GetMemberNames() {
  388. return PythonOps.GetStringMemberList(this);
  389. }
  390. IList<object> IPythonMembersList.GetMemberNames(CodeContext/*!*/ context) {
  391. object o;
  392. if (!TryGetObject(out o)) {
  393. // if we've been disconnected return an empty list
  394. return new List();
  395. }
  396. return PythonOps.GetAttrNames(context, o);
  397. }
  398. #endregion
  399. #region IProxyObject Members
  400. object IProxyObject.Target {
  401. get { return GetObject(); }
  402. }
  403. #endregion
  404. #region IValueEquality Members
  405. #if CLR2
  406. int IValueEquality.GetValueHashCode() {
  407. throw PythonOps.TypeErrorForUnhashableType("weakproxy");
  408. }
  409. bool IValueEquality.ValueEquals(object other) {
  410. weakproxy wrp = other as weakproxy;
  411. if (wrp != null) return EqualsWorker(wrp);
  412. return PythonOps.EqualRetBool(_context, GetObject(), other);
  413. }
  414. #endif
  415. #endregion
  416. #region IStructuralEquatable Members
  417. public const object __hash__ = null;
  418. private bool EqualsWorker(weakproxy other) {
  419. return PythonOps.EqualRetBool(_context, GetObject(), other.GetObject());
  420. }
  421. /// <summary>
  422. /// Special equality function because IStructuralEquatable.Equals is not allowed to throw.
  423. /// </summary>
  424. [return: MaybeNotImplemented]
  425. public object __eq__(object other) {
  426. if (!(other is weakproxy)) return NotImplementedType.Value;
  427. return ScriptingRuntimeHelpers.BooleanToObject(EqualsWorker((weakproxy)other));
  428. }
  429. [return: MaybeNotImplemented]
  430. public object __ne__(object other) {
  431. if (!(other is weakproxy)) return NotImplementedType.Value;
  432. return ScriptingRuntimeHelpers.BooleanToObject(!EqualsWorker((weakproxy)other));
  433. }
  434. int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
  435. object obj;
  436. if (TryGetObject(out obj)) {
  437. return comparer.GetHashCode(obj);
  438. }
  439. return comparer.GetHashCode(null);
  440. }
  441. bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) {
  442. object obj;
  443. if (!TryGetObject(out obj)) {
  444. obj = null;
  445. }
  446. weakproxy wrp = other as weakproxy;
  447. if (wrp != null) {
  448. object otherObj;
  449. if (!TryGetObject(out otherObj)) {
  450. otherObj = null;
  451. }
  452. return comparer.Equals(obj, otherObj);
  453. }
  454. return comparer.Equals(obj, other);
  455. }
  456. #endregion
  457. public object __nonzero__() {
  458. return Converter.ConvertToBoolean(GetObject());
  459. }
  460. public static explicit operator bool(weakproxy self) {
  461. return Converter.ConvertToBoolean(self.GetObject());
  462. }
  463. }
  464. [PythonType, DynamicBaseTypeAttribute, PythonHidden]
  465. public sealed partial class weakcallableproxy :
  466. IPythonObject,
  467. ICodeFormattable,
  468. IProxyObject,
  469. IStructuralEquatable,
  470. #if CLR2
  471. IValueEquality,
  472. #endif
  473. IPythonMembersList {
  474. private WeakHandle _target;
  475. private readonly CodeContext/*!*/ _context;
  476. #region Python Constructors
  477. internal static object MakeNew(CodeContext/*!*/ context, object @object, object callback) {
  478. IWeakReferenceable iwr = ConvertToWeakReferenceable(@object);
  479. if (callback == null) {
  480. WeakRefTracker wrt = iwr.GetWeakRef();
  481. if (wrt != null) {
  482. for (int i = 0; i < wrt.HandlerCount; i++) {
  483. if (wrt.GetHandlerCallback(i) == null &&
  484. wrt.GetWeakRef(i) is weakcallableproxy) {
  485. return wrt.GetWeakRef(i);
  486. }
  487. }
  488. }
  489. }
  490. return new weakcallableproxy(context, @object, callback);
  491. }
  492. #endregion
  493. #region Constructors
  494. private weakcallableproxy(CodeContext context, object target, object callback) {
  495. WeakRefHelpers.InitializeWeakRef(this, target, callback);
  496. _target = new WeakHandle(target, false);
  497. _context = context;
  498. }
  499. #endregion
  500. #region Finalizer
  501. ~weakcallableproxy() {
  502. // remove our self from the chain...
  503. try {
  504. IWeakReferenceable iwr = _target.Target as IWeakReferenceable;
  505. if (iwr != null) {
  506. WeakRefTracker wrt = iwr.GetWeakRef();
  507. wrt.RemoveHandler(this);
  508. }
  509. _target.Free();
  510. } catch (InvalidOperationException) {
  511. // target was freed
  512. }
  513. }
  514. #endregion
  515. #region private members
  516. /// <summary>
  517. /// gets the object or throws a reference exception
  518. /// </summary>
  519. private object GetObject() {
  520. object res;
  521. if (!TryGetObject(out res)) {
  522. throw PythonOps.ReferenceError("weakly referenced object no longer exists");
  523. }
  524. return res;
  525. }
  526. private bool TryGetObject(out object result) {
  527. try {
  528. result = _target.Target;
  529. if (result == null) return false;
  530. GC.KeepAlive(this);
  531. return true;
  532. } catch (InvalidOperationException) {
  533. result = null;
  534. return false;
  535. }
  536. }
  537. #endregion
  538. #region IPythonObject Members
  539. PythonDictionary IPythonObject.Dict {
  540. get {
  541. return (GetObject() as IPythonObject).Dict;
  542. }
  543. }
  544. PythonDictionary IPythonObject.SetDict(PythonDictionary dict) {
  545. return (GetObject() as IPythonObject).SetDict(dict);
  546. }
  547. bool IPythonObject.ReplaceDict(PythonDictionary dict) {
  548. return (GetObject() as IPythonObject).ReplaceDict(dict);
  549. }
  550. void IPythonObject.SetPythonType(PythonType newType) {
  551. (GetObject() as IPythonObject).SetPythonType(newType);
  552. }
  553. PythonType IPythonObject.PythonType {
  554. get {
  555. return DynamicHelpers.GetPythonTypeFromType(typeof(weakcallableproxy));
  556. }
  557. }
  558. object[] IPythonObject.GetSlots() { return null; }
  559. object[] IPythonObject.GetSlotsCreate() { return null; }
  560. #endregion
  561. #region object overloads
  562. public override string ToString() {
  563. return PythonOps.ToString(GetObject());
  564. }
  565. #endregion
  566. #region ICodeFormattable Members
  567. public string/*!*/ __repr__(CodeContext/*!*/ context) {
  568. object obj = _target.Target;
  569. GC.KeepAlive(this);
  570. return String.Format("<weakproxy at {0} to {1} at {2}>",
  571. IdDispenser.GetId(this),
  572. PythonOps.GetPythonTypeName(obj),
  573. IdDispenser.GetId(obj));
  574. }
  575. #endregion
  576. [SpecialName]
  577. public object Call(CodeContext/*!*/ context, params object[] args) {
  578. return PythonContext.GetContext(context).CallSplat(GetObject(), args);
  579. }
  580. [SpecialName]
  581. public object Call(CodeContext/*!*/ context, [ParamDictionary]IDictionary<object, object> dict, params object[] args) {
  582. return PythonCalls.CallWithKeywordArgs(context, GetObject(), args, dict);
  583. }
  584. #region Custom members access
  585. [SpecialName]
  586. public object GetCustomMember(CodeContext/*!*/ context, string name) {
  587. object o = GetObject();
  588. object value;
  589. if (PythonOps.TryGetBoundAttr(context, o, name, out value)) {
  590. return value;
  591. }
  592. return OperationFailed.Value;
  593. }
  594. [SpecialName]
  595. public void SetMember(CodeContext/*!*/ context, string name, object value) {
  596. object o = GetObject();
  597. PythonOps.SetAttr(context, o, name, value);
  598. }
  599. [SpecialName]
  600. public void DeleteMember(CodeContext/*!*/ context, string name) {
  601. object o = GetObject();
  602. PythonOps.DeleteAttr(context, o, name);
  603. }
  604. IList<string> IMembersList.GetMemberNames() {
  605. return PythonOps.GetStringMemberList(this);
  606. }
  607. IList<object> IPythonMembersList.GetMemberNames(CodeContext/*!*/ context) {
  608. object o;
  609. if (!TryGetObject(out o)) {
  610. // if we've been disconnected return an empty list
  611. return new List();
  612. }
  613. return PythonOps.GetAttrNames(context, o);
  614. }
  615. #endregion
  616. #region IProxyObject Members
  617. object IProxyObject.Target {
  618. get { return GetObject(); }
  619. }
  620. #endregion
  621. #region IValueEquality Members
  622. #if CLR2
  623. int IValueEquality.GetValueHashCode() {
  624. throw PythonOps.TypeErrorForUnhashableType("weakcallableproxy");
  625. }
  626. bool IValueEquality.ValueEquals(object other) {
  627. return __eq__(other);
  628. }
  629. #endif
  630. #endregion
  631. #region IStructuralEquatable Members
  632. public const object __hash__ = null;
  633. /// <summary>
  634. /// Special equality function because IStructuralEquatable.Equals is not allowed to throw.
  635. /// </summary>
  636. public bool __eq__(object other) {
  637. weakcallableproxy wrp = other as weakcallableproxy;
  638. if (wrp != null) return GetObject().Equals(wrp.GetObject());
  639. return PythonOps.EqualRetBool(_context, GetObject(), other);
  640. }
  641. public bool __ne__(object other) {
  642. return !__eq__(other);
  643. }
  644. int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
  645. object obj;
  646. if (TryGetObject(out obj)) {
  647. return comparer.GetHashCode(obj);
  648. }
  649. return comparer.GetHashCode(null);
  650. }
  651. bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) {
  652. object obj;
  653. if (!TryGetObject(out obj)) {
  654. obj = null;
  655. }
  656. weakcallableproxy wrp = other as weakcallableproxy;
  657. if (wrp != null) {
  658. object otherObj;
  659. if (!TryGetObject(out otherObj)) {
  660. otherObj = null;
  661. }
  662. return comparer.Equals(obj, otherObj);
  663. }
  664. return comparer.Equals(obj, other);
  665. }
  666. #endregion
  667. public object __nonzero__() {
  668. return Converter.ConvertToBoolean(GetObject());
  669. }
  670. }
  671. static class WeakRefHelpers {
  672. public static void InitializeWeakRef(object self, object target, object callback) {
  673. IWeakReferenceable iwr = ConvertToWeakReferenceable(target);
  674. WeakRefTracker wrt = iwr.GetWeakRef();
  675. if (wrt == null) {
  676. if (!iwr.SetWeakRef(new WeakRefTracker(callback, self))) {
  677. throw PythonOps.TypeError("cannot create weak reference to '{0}' object", PythonOps.GetPythonTypeName(target));
  678. }
  679. } else {
  680. wrt.ChainCallback(callback, self);
  681. }
  682. }
  683. }
  684. }
  685. [PythonType("wrapper_descriptor")]
  686. class SlotWrapper : PythonTypeSlot, ICodeFormattable {
  687. private readonly string _name;
  688. private readonly PythonType _type;
  689. public SlotWrapper(string slotName, PythonType targetType) {
  690. _name = slotName;
  691. _type = targetType;
  692. }
  693. #region ICodeFormattable Members
  694. public virtual string/*!*/ __repr__(CodeContext/*!*/ context) {
  695. return String.Format("<slot wrapper {0} of {1} objects>",
  696. PythonOps.Repr(context, _name),
  697. PythonOps.Repr(context, _type.Name));
  698. }
  699. #endregion
  700. #region PythonTypeSlot Overrides
  701. internal override bool TryGetValue(CodeContext context, object instance, PythonType owner, out object value) {
  702. if (instance == null) {
  703. value = this;
  704. return true;
  705. }
  706. IProxyObject proxy = instance as IProxyObject;
  707. if (proxy == null)
  708. throw PythonOps.TypeError("descriptor for {0} object doesn't apply to {1} object",
  709. PythonOps.Repr(context, _type.Name),
  710. PythonOps.Repr(context, PythonTypeOps.GetName(instance)));
  711. if (!DynamicHelpers.GetPythonType(proxy.Target).TryGetBoundMember(context, proxy.Target, _name, out value))
  712. return false;
  713. value = new GenericMethodWrapper(_name, proxy);
  714. return true;
  715. }
  716. #endregion
  717. }
  718. [PythonType("method-wrapper")]
  719. public class GenericMethodWrapper {
  720. string name;
  721. IProxyObject target;
  722. public GenericMethodWrapper(string methodName, IProxyObject proxyTarget) {
  723. name = methodName;
  724. target = proxyTarget;
  725. }
  726. [SpecialName]
  727. public object Call(CodeContext context, params object[] args) {
  728. return PythonOps.Invoke(context, target.Target, name, args);
  729. }
  730. [SpecialName]
  731. public object Call(CodeContext context, [ParamDictionary]IDictionary<object, object> dict, params object[] args) {
  732. object targetMethod;
  733. if (!DynamicHelpers.GetPythonType(target.Target).TryGetBoundMember(context, target.Target, name, out targetMethod))
  734. throw PythonOps.AttributeError("type {0} has no attribute {1}",
  735. DynamicHelpers.GetPythonType(target.Target),
  736. name);
  737. return PythonCalls.CallWithKeywordArgs(context, targetMethod, args, dict);
  738. }
  739. }
  740. }