PageRenderTime 52ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/IronPython/IronPython.Modules/_weakref.cs

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