// This file was generated by the Gtk# code generator.
// Any changes made will be lost if regenerated.

namespace Gst.Net {

	using System;
	using System.Collections;
	using System.Collections.Generic;
	using System.Runtime.InteropServices;

#region Autogenerated code
	[StructLayout(LayoutKind.Sequential)]
	public partial struct NetAddressMeta : IEquatable<NetAddressMeta> {

		public Gst.Meta Meta;
		private IntPtr _addr;
		public GLib.SocketAddress Addr {
			get {
				return GLib.Object.GetObject(_addr) as GLib.SocketAddress;
			}
			set {
				_addr = value == null ? IntPtr.Zero : value.Handle;
			}
		}

		public static Gst.Net.NetAddressMeta Zero = new Gst.Net.NetAddressMeta ();

		public static Gst.Net.NetAddressMeta New(IntPtr raw) {
			if (raw == IntPtr.Zero)
				return Gst.Net.NetAddressMeta.Zero;
			return (Gst.Net.NetAddressMeta) Marshal.PtrToStructure (raw, typeof (Gst.Net.NetAddressMeta));
		}

		[DllImport("gstnet-1.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
		static extern IntPtr gst_net_address_meta_get_info();

		public static Gst.MetaInfo Info { 
			get {
				IntPtr raw_ret = gst_net_address_meta_get_info();
				Gst.MetaInfo ret = Gst.MetaInfo.New (raw_ret);
				return ret;
			}
		}

		public bool Equals (NetAddressMeta other)
		{
			return true && Meta.Equals (other.Meta) && Addr.Equals (other.Addr);
		}

		public override bool Equals (object other)
		{
			return other is NetAddressMeta && Equals ((NetAddressMeta) other);
		}

		public override int GetHashCode ()
		{
			return this.GetType ().FullName.GetHashCode () ^ Meta.GetHashCode () ^ Addr.GetHashCode ();
		}

		private static GLib.GType GType {
			get { return GLib.GType.Pointer; }
		}
#endregion
	}
}
