 doc/src/sgml/custom-scan.sgml     | 115 +++++++++++++++++++++++++++++---------
 src/backend/commands/explain.c    |   2 +-
 src/backend/executor/nodeCustom.c |   4 +-
 src/backend/nodes/copyfuncs.c     |  19 +++++--
 src/backend/nodes/nodes.c         |  82 +++++++++++++++++++++++++++
 src/backend/nodes/outfuncs.c      |  30 +++++++---
 src/backend/nodes/readfuncs.c     |  46 ++++++++++-----
 src/include/nodes/execnodes.h     |   2 +-
 src/include/nodes/nodes.h         |  18 ++++++
 src/include/nodes/plannodes.h     |   5 +-
 src/include/nodes/relation.h      |   6 +-
 11 files changed, 269 insertions(+), 60 deletions(-)

diff --git a/doc/src/sgml/custom-scan.sgml b/doc/src/sgml/custom-scan.sgml
index 5bba125..933a9bd 100644
--- a/doc/src/sgml/custom-scan.sgml
+++ b/doc/src/sgml/custom-scan.sgml
@@ -78,14 +78,16 @@ typedef struct CustomPath
     nodes used by this custom-path node; these will be transformed into
     <structname>Plan</> nodes by planner.
     <structfield>custom_private</> can be used to store the custom path's
-    private data.  Private data should be stored in a form that can be handled
-    by <literal>nodeToString</>, so that debugging routines that attempt to
-    print the custom path will work as designed.  <structfield>methods</> must
-    point to a (usually statically allocated) object implementing the required
-    custom path methods, of which there is currently only one.  The
-    <structfield>LibraryName</> and <structfield>SymbolName</> fields must also
-    be initialized so that the dynamic loader can resolve them to locate the
-    method table.
+    private data. Private data should be stored in a form that can be handled
+    by <literal>nodeToString</>. <structfield>methods</> must point to a
+    (usually statically allocated) object implementing the required custom
+    path methods, of which there is currently only one.
+    The first field of <structname>CustomPathMethods</> is
+    <structname>ExtensibleNodeMethods</>. If custom scan provider defines
+    own structure larger than <structname>CustomPathMethods</> to keep
+    private information on the extra area, it must support callbacks of
+    the <structname>ExtensibleNodeMethods</> to treat these private fields.
+    See <xref linkend="custom-private-structure"> for more details.
   </para>
 
   <para>
@@ -125,19 +127,6 @@ Plan *(*PlanCustomPath) (PlannerInfo *root,
     be a <literal>CustomScan</> object, which the callback must allocate and
     initialize.  See <xref linkend="custom-scan-plan"> for more details.
    </para>
-
-   <para>
-<programlisting>
-void (*TextOutCustomPath) (StringInfo str,
-                           const CustomPath *node);
-</programlisting>
-    Generate additional output when <function>nodeToString</> is invoked on
-    this custom path.  This callback is optional.  Since
-    <function>nodeToString</> will automatically dump all fields in the
-    structure that it can see, including <structfield>custom_private</>, this
-    is only useful if the <structname>CustomPath</> is actually embedded in a
-    larger struct containing additional fields.
-   </para>
   </sect2>
  </sect1>
 
@@ -198,10 +187,15 @@ typedef struct CustomScan
   <para>
    Plan trees must be able to be duplicated using <function>copyObject</>,
    so all the data stored within the <quote>custom</> fields must consist of
-   nodes that that function can handle.  Furthermore, custom scan providers
-   cannot substitute a larger structure that embeds
-   a <structname>CustomScan</> for the structure itself, as would be possible
-   for a <structname>CustomPath</> or <structname>CustomScanState</>.
+   nodes that that function can handle. In case when custom scan providers
+   can substitute a larger structure that embeds a <structname>CustomScan</>
+   for the structure itself, as would be possible for <structname>CustomPath</>
+   or <structname>CustomScanState</>.
+   If custom scan provider keeps its private fields in the extra area of the
+   above own defined structure, it also have to implement each callbacks of
+   <structname>ExtensibleNodeMethods</> to support serialization and
+   deserialization.
+   See <xref linkend="custom-scan-plan"> for more details.
   </para>
 
   <sect2 id="custom-scan-plan-callbacks">
@@ -328,4 +322,75 @@ void (*ExplainCustomScan) (CustomScanState *node,
    </para>
   </sect2>
  </sect1>
+
+ <sect1 id="custom-private-structure">
+  <title>Private fields with own structure</title>
+  <para>
+   Some node types, like <structname>CustomScan</> or
+   <structname>ForeignScan</>, allows extension to have itself as a part of
+   larger structure for their private fields with arbitrary forms.
+   In this case, extension has to ensure its private fields are kept
+   correctly on node operations, like copy, serialization and deserialization.
+  </para>
+  <para>
+   <structname>ExtensibleNodeMethods</> is a collection of callbacks that
+   enable extension to get control on node operations, to process its private
+   fields.
+   All the <structname>ExtensibleNodeMethods</> implementation has to be
+   registered with a unique name. It is key to lookup proper collection of
+   the callbacks later. Usually, it shall be done on <funcation>_PG_init</>.
+  </para>
+  <para>
+   Specification of the individual callbacks are below.
+  </para>
+  <para>
+<programlisting>
+const char *extnodename;
+</programlisting>
+   A unique name of this collection of the node operations callback.
+   It should not be duplicated with one preliminary registered.
+  </para>
+  <para>
+<programlisting>
+Size    node_size;
+</programlisting>
+   Size of the self define structure. Of course, it has to be larger
+   than or equal to the structure to be embedded in.
+  </para>
+  <para>
+<programlisting>
+void    nodeCopy(Node *newnode, const Node *oldnode);
+</programlisting>
+   This callback copies the private fields on <varname>oldnode</> to
+   the <varname>newnode</>. Extension does not need to copy the known
+   fields in the structure that is embedded in; it is the responsibility
+   of the core backend.
+  </para>
+  <para>
+<programlisting>
+Size    nodeEqual(const Node *a, const Node *b);
+</programlisting>
+   This callback compares private fields on <varname>a</> and <varname>b</>,
+   then returns <literal>true</> if equivalent. Elsewhere, <literal>false</>.
+  </para>
+  <para>
+<programlisting>
+Size    nodeOut(StringInfo str, const Node *node);
+</programlisting>
+   This callback serializes the private fields in text form, then put this
+   string on the supplied <structname>StringInfo</>. All extension has to
+   write out is its own private fields. The known fields on the structure
+   embedded in are written out by the core backend.
+  </para>
+  <para>
+<programlisting>
+Size    nodeRead(Node *node);
+</programlisting>
+   This callback deserializes the private fields, written by the above
+   <function>nodeOut</>, on the supplied <varname>node</> object.
+   So, these callbacks have to be always symmetric.
+   It shall be invoked in the context of <function>stringToNode</>, thus
+   <function>pg_strtok</> will fetch next token to read.
+  </para>
+ </sect1>
 </chapter>
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 183d3d9..2986308 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -891,7 +891,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
 			break;
 		case T_CustomScan:
 			sname = "Custom Scan";
-			custom_name = ((CustomScan *) plan)->methods->CustomName;
+			custom_name = ((CustomScan *) plan)->methods->xnode.extnodename;
 			if (custom_name)
 				pname = psprintf("Custom Scan (%s)", custom_name);
 			else
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index 0a022df..553fe96 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -145,7 +145,7 @@ ExecCustomMarkPos(CustomScanState *node)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("custom-scan \"%s\" does not support MarkPos",
-						node->methods->CustomName)));
+						node->methods->xnode.extnodename)));
 	node->methods->MarkPosCustomScan(node);
 }
 
@@ -156,6 +156,6 @@ ExecCustomRestrPos(CustomScanState *node)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("custom-scan \"%s\" does not support MarkPos",
-						node->methods->CustomName)));
+						node->methods->xnode.extnodename)));
 	node->methods->RestrPosCustomScan(node);
 }
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 26264cb..c4bb76e 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -635,8 +635,12 @@ _copyWorkTableScan(const WorkTableScan *from)
 static ForeignScan *
 _copyForeignScan(const ForeignScan *from)
 {
-	ForeignScan *newnode = makeNode(ForeignScan);
-
+	const ExtensibleNodeMethods *methods
+		= GetExtensibleNodeMethods(from->extnodename, true);
+	ForeignScan *newnode = (ForeignScan *) newNode(!methods
+												   ? sizeof(ForeignScan)
+												   : methods->node_size,
+												   T_ForeignScan);
 	/*
 	 * copy node superclass fields
 	 */
@@ -645,6 +649,7 @@ _copyForeignScan(const ForeignScan *from)
 	/*
 	 * copy remainder of node
 	 */
+	COPY_STRING_FIELD(extnodename);
 	COPY_SCALAR_FIELD(fs_server);
 	COPY_NODE_FIELD(fdw_exprs);
 	COPY_NODE_FIELD(fdw_private);
@@ -652,6 +657,8 @@ _copyForeignScan(const ForeignScan *from)
 	COPY_NODE_FIELD(fdw_recheck_quals);
 	COPY_BITMAPSET_FIELD(fs_relids);
 	COPY_SCALAR_FIELD(fsSystemCol);
+	if (methods && methods->nodeCopy)
+		methods->nodeCopy((Node *) newnode, (const Node *) from);
 
 	return newnode;
 }
@@ -662,8 +669,9 @@ _copyForeignScan(const ForeignScan *from)
 static CustomScan *
 _copyCustomScan(const CustomScan *from)
 {
-	CustomScan *newnode = makeNode(CustomScan);
-
+	const ExtensibleNodeMethods *methods = &from->methods->xnode;
+	CustomScan *newnode = (CustomScan *) newNode(methods->node_size,
+												 T_CustomScan);
 	/*
 	 * copy node superclass fields
 	 */
@@ -686,6 +694,9 @@ _copyCustomScan(const CustomScan *from)
 	 */
 	COPY_SCALAR_FIELD(methods);
 
+	if (methods->nodeCopy)
+		methods->nodeCopy((Node *) newnode, (const Node *) from);
+
 	return newnode;
 }
 
diff --git a/src/backend/nodes/nodes.c b/src/backend/nodes/nodes.c
index 9c0b3fe..f8dd993 100644
--- a/src/backend/nodes/nodes.c
+++ b/src/backend/nodes/nodes.c
@@ -19,6 +19,9 @@
 #include "postgres.h"
 
 #include "nodes/nodes.h"
+#include "nodes/pg_list.h"
+#include "utils/hsearch.h"
+#include "utils/memutils.h"
 
 /*
  * Support for newNode() macro
@@ -29,3 +32,82 @@
  */
 
 Node	   *newNodeMacroHolder;
+
+/*
+ * Extensible node support - We allow extension to have own structure that
+ * contains well known structure (like ForeignScan or CustomScan), to keep
+ * their private data fields. These structure also have to support
+ * serialization / deserialization using node functions. A collection of
+ * callback enables to handle private fields also, not only well known
+ * portion.
+ */
+#define XNODES_NUM_SLOTS	256
+static List	  **xnodes_methods_slots = NULL;
+
+void
+RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *methods)
+{
+	uint32			hash;
+	int				index;
+	ListCell	   *lc;
+	MemoryContext	oldcxt;
+
+	if (!xnodes_methods_slots)
+		xnodes_methods_slots = MemoryContextAllocZero(TopMemoryContext,
+										  sizeof(List *) * XNODES_NUM_SLOTS);
+
+	hash = hash_any(methods->extnodename, strlen(methods->extnodename));
+	index = hash % XNODES_NUM_SLOTS;
+
+	/* duplication check */
+	foreach (lc, xnodes_methods_slots[index])
+	{
+		const ExtensibleNodeMethods *curr = lfirst(lc);
+
+		if (strcmp(methods->extnodename, curr->extnodename) == 0)
+			ereport(ERROR,
+					(errcode(ERRCODE_DUPLICATE_OBJECT),
+					 errmsg("ExtensibleNodeMethods \"%s\" already exists",
+							methods->extnodename)));
+	}
+	/* ok, register this entry */
+	oldcxt = MemoryContextSwitchTo(TopMemoryContext);
+	xnodes_methods_slots[index] = lappend(xnodes_methods_slots[index],
+										  (void *)methods);
+	MemoryContextSwitchTo(oldcxt);
+}
+
+const ExtensibleNodeMethods *
+GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
+{
+	const ExtensibleNodeMethods *methods = NULL;
+
+	if (!extnodename)
+		return NULL;
+
+	if (xnodes_methods_slots)
+	{
+		uint32		hash = hash_any(extnodename, strlen(extnodename));
+		int			index = hash % XNODES_NUM_SLOTS;
+		ListCell   *lc;
+
+		/* search the registered table */
+		foreach (lc, xnodes_methods_slots[index])
+		{
+			const ExtensibleNodeMethods *curr = lfirst(lc);
+
+			if (strcmp(curr->extnodename, extnodename) == 0)
+			{
+				methods = curr;
+				break;
+			}
+		}
+	}
+
+	if (!methods && !missing_ok)
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("ExtensibleNodeMethods \"%s\" was not registered",
+						extnodename)));
+	return methods;
+}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 012c14b..3903aea 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -587,6 +587,9 @@ _outWorkTableScan(StringInfo str, const WorkTableScan *node)
 static void
 _outForeignScan(StringInfo str, const ForeignScan *node)
 {
+	const ExtensibleNodeMethods *methods
+		= GetExtensibleNodeMethods(node->extnodename, true);
+
 	WRITE_NODE_TYPE("FOREIGNSCAN");
 
 	_outScanInfo(str, (const Scan *) node);
@@ -598,11 +601,15 @@ _outForeignScan(StringInfo str, const ForeignScan *node)
 	WRITE_NODE_FIELD(fdw_recheck_quals);
 	WRITE_BITMAPSET_FIELD(fs_relids);
 	WRITE_BOOL_FIELD(fsSystemCol);
+	if (methods && methods->nodeOut)
+		methods->nodeOut(str, (const Node *) node);
 }
 
 static void
 _outCustomScan(StringInfo str, const CustomScan *node)
 {
+	const ExtensibleNodeMethods *methods = &node->methods->xnode;
+
 	WRITE_NODE_TYPE("CUSTOMSCAN");
 
 	_outScanInfo(str, (const Scan *) node);
@@ -613,11 +620,12 @@ _outCustomScan(StringInfo str, const CustomScan *node)
 	WRITE_NODE_FIELD(custom_private);
 	WRITE_NODE_FIELD(custom_scan_tlist);
 	WRITE_BITMAPSET_FIELD(custom_relids);
-	/* Dump library and symbol name instead of raw pointer */
+	/* Dump CustomName; alias of extnodename */
 	appendStringInfoString(str, " :methods ");
-	_outToken(str, node->methods->LibraryName);
-	appendStringInfoChar(str, ' ');
-	_outToken(str, node->methods->SymbolName);
+	_outToken(str, methods->extnodename);
+	/* Dump private fields if any */
+	if (methods && methods->nodeOut)
+		methods->nodeOut(str, (const Node *) node);
 }
 
 static void
@@ -1679,16 +1687,24 @@ _outTidPath(StringInfo str, const TidPath *node)
 static void
 _outForeignPath(StringInfo str, const ForeignPath *node)
 {
+	const ExtensibleNodeMethods *methods
+		= GetExtensibleNodeMethods(node->extnodename, true);
+
 	WRITE_NODE_TYPE("FOREIGNPATH");
 
 	_outPathInfo(str, (const Path *) node);
 
+	WRITE_STRING_FIELD(extnodename);
 	WRITE_NODE_FIELD(fdw_private);
+	if (methods && methods->nodeOut)
+		methods->nodeOut(str, (Node *) node);
 }
 
 static void
 _outCustomPath(StringInfo str, const CustomPath *node)
 {
+	const ExtensibleNodeMethods *methods = &node->methods->xnode;
+
 	WRITE_NODE_TYPE("CUSTOMPATH");
 
 	_outPathInfo(str, (const Path *) node);
@@ -1697,9 +1713,9 @@ _outCustomPath(StringInfo str, const CustomPath *node)
 	WRITE_NODE_FIELD(custom_paths);
 	WRITE_NODE_FIELD(custom_private);
 	appendStringInfoString(str, " :methods ");
-	_outToken(str, node->methods->CustomName);
-	if (node->methods->TextOutCustomPath)
-		node->methods->TextOutCustomPath(str, node);
+	_outToken(str, methods->extnodename);
+	if (methods && methods->nodeOut)
+		methods->nodeOut(str, (Node *)node);
 }
 
 static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 222e2ed..00e81b7 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1792,10 +1792,12 @@ _readWorkTableScan(void)
 static ForeignScan *
 _readForeignScan(void)
 {
+	const ExtensibleNodeMethods *methods;
 	READ_LOCALS(ForeignScan);
 
 	ReadCommonScan(&local_node->scan);
 
+	READ_STRING_FIELD(extnodename);
 	READ_OID_FIELD(fs_server);
 	READ_NODE_FIELD(fdw_exprs);
 	READ_NODE_FIELD(fdw_private);
@@ -1804,6 +1806,19 @@ _readForeignScan(void)
 	READ_BITMAPSET_FIELD(fs_relids);
 	READ_BOOL_FIELD(fsSystemCol);
 
+	methods = GetExtensibleNodeMethods(local_node->extnodename, true);
+	if (methods && methods->nodeRead)
+	{
+		ForeignScan	   *local_temp = palloc0(methods->node_size);
+
+		Assert(methods->node_size >= sizeof(ForeignScan));
+
+		memcpy(local_temp, local_node, sizeof(ForeignScan));
+		methods->nodeRead((Node *) local_temp);
+
+		pfree(local_node);
+		local_node = local_temp;
+	}
 	READ_DONE();
 }
 
@@ -1813,10 +1828,9 @@ _readForeignScan(void)
 static CustomScan *
 _readCustomScan(void)
 {
+	const ExtensibleNodeMethods *methods;
+	const char	   *extnodename;
 	READ_LOCALS(CustomScan);
-	char	   *library_name;
-	char	   *symbol_name;
-	const CustomScanMethods *methods;
 
 	ReadCommonScan(&local_node->scan);
 
@@ -1831,18 +1845,24 @@ _readCustomScan(void)
 	 * Reconstruction of methods using library and symbol name
 	 */
 	token = pg_strtok(&length);		/* skip methods: */
-	token = pg_strtok(&length);		/* LibraryName */
-	library_name = nullable_string(token, length);
-	token = pg_strtok(&length);		/* SymbolName */
-	symbol_name = nullable_string(token, length);
+	token = pg_strtok(&length);		/* CustomName (alias of extnodename) */
+	extnodename = nullable_string(token, length);
+	methods = GetExtensibleNodeMethods(extnodename, false);
 
-	methods = (const CustomScanMethods *)
-		load_external_function(library_name, symbol_name, true, NULL);
-	Assert(strcmp(methods->LibraryName, library_name) == 0 &&
-		   strcmp(methods->SymbolName, symbol_name) == 0);
-	local_node->methods = methods;
+	if (methods->nodeRead)
+	{
+		CustomScan	   *local_temp = palloc0(methods->node_size);
 
-	READ_DONE();
+		Assert(methods->node_size >= sizeof(CustomScan));
+		memcpy(local_temp, local_node, sizeof(CustomScan));
+		methods->nodeRead((Node *) local_temp);
+
+		pfree(local_node);
+		local_node = local_temp;
+	}
+	local_node->methods = (const CustomScanMethods *) methods;
+
+    READ_DONE();
 }
 
 /*
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index eb3591a..9e79049 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1607,7 +1607,7 @@ struct CustomScanState;
 
 typedef struct CustomExecMethods
 {
-	const char *CustomName;
+	ExtensibleNodeMethods xnode;	/* collection of node operations */
 
 	/* Executor methods: mark/restore are optional, the rest are required */
 	void		(*BeginCustomScan) (struct CustomScanState *node,
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 94bdb7c..0ac4565 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -542,6 +542,24 @@ extern void *copyObject(const void *obj);
  */
 extern bool equal(const void *a, const void *b);
 
+/*
+ * ExtensibleNodeMethods - a collection of node operation callbacks.
+ */
+struct StringInfoData;		/* not to include stringinfo.h here */
+
+typedef struct ExtensibleNodeMethods
+{
+	const char *extnodename;
+	Size		node_size;
+	void	  (*nodeCopy)(Node *newnode, const Node *oldnode);
+	bool	  (*nodeEqual)(const Node *a, const Node *b);
+	void	  (*nodeOut)(struct StringInfoData *str, const Node *node);
+	void	  (*nodeRead)(Node *node);
+} ExtensibleNodeMethods;
+
+extern void RegisterExtensibleNodeMethods(const ExtensibleNodeMethods *method);
+extern const ExtensibleNodeMethods *GetExtensibleNodeMethods(const char *name,
+															 bool missing_ok);
 
 /*
  * Typedefs for identifying qualifier selectivities and plan costs as such.
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 37086c6..9b99f65 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -530,6 +530,7 @@ typedef struct WorkTableScan
 typedef struct ForeignScan
 {
 	Scan		scan;
+	const char *extnodename;	/* collection of node operation callbacks */
 	Oid			fs_server;		/* OID of foreign server */
 	List	   *fdw_exprs;		/* expressions that FDW may evaluate */
 	List	   *fdw_private;	/* private data for FDW */
@@ -556,9 +557,7 @@ struct CustomScan;
 
 typedef struct CustomScanMethods
 {
-	const char *CustomName;
-	const char *LibraryName;
-	const char *SymbolName;
+	ExtensibleNodeMethods xnode;	/* collection of node operations */
 
 	/* Create execution state (CustomScanState) from a CustomScan plan node */
 	Node	   *(*CreateCustomScanState) (struct CustomScan *cscan);
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 9a0dd28..8e4d735 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -909,6 +909,7 @@ typedef struct TidPath
 typedef struct ForeignPath
 {
 	Path		path;
+	const char *extnodename;
 	List	   *fdw_private;
 } ForeignPath;
 
@@ -937,7 +938,7 @@ struct CustomPath;
 
 typedef struct CustomPathMethods
 {
-	const char *CustomName;
+	ExtensibleNodeMethods xnode;	/* collection of node operations */
 
 	/* Convert Path to a Plan */
 	struct Plan *(*PlanCustomPath) (PlannerInfo *root,
@@ -946,9 +947,6 @@ typedef struct CustomPathMethods
 												List *tlist,
 												List *clauses,
 												List *custom_plans);
-	/* Optional: print additional fields besides "private" */
-	void		(*TextOutCustomPath) (StringInfo str,
-											  const struct CustomPath *node);
 } CustomPathMethods;
 
 typedef struct CustomPath
